You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Matlab的机械臂逆运动学3D建模点位对齐问题求助

机械足逆运动学Matlab 3D可视化点位对齐问题

背景与现有Python实现

已完成机械足逆运动学数学推导,现有Python版3D可视化代码如下:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.widgets import Slider, RadioButtons
import numpy as np
import math


def calculate_line(length, angle, axis):
    # Convert angle to radians
    angle_rad = np.radians(angle)
    # Calculate coordinates of the line based on the selected axis
    if axis == 'XY':
        x = [0, length * np.cos(angle_rad)]
        y = [0, length * np.sin(angle_rad)]
        z = [0, 0]
    elif axis == 'XZ':
        x = [0, length * np.cos(angle_rad)]
        y = [0, 0]
        z = [0, length * np.sin(angle_rad)]
    elif axis == 'YZ':
        x = [0, 0]
        y = [0, length * np.cos(angle_rad)]
        z = [0, length * np.sin(angle_rad)]
    return x, y, z


coax =35
femur = 120
tibia = 140

def update(val):
    rz= rh_slider.val
    
    fz=fz_slider.val
    fy=fy_slider.val
    fx=fx_slider.val
    b1=fy
    b2=coax
    a1=rz
    
    ax.clear()
    ax.plot([0, 0], [0,0], [0, rz ], color='green', label='')
    ax.plot([0, 300], [0,0], [rz, rz ], color='green', label='robot length')
    ax.plot([300, 300], [0,0], [0, rz ], color='green', label='')
    ax.plot([0, 0], [0,150], [rz, rz ], color='green', label='robot width')
    ax.plot([0, 0], [0,150], [rz, rz ], color='green', label='')
    ax.plot([0, 300], [150,150], [rz, rz ], color='green', label='')
    ax.plot([300, 300], [150,0], [rz, rz ], color='green', label='')
    
    print(f'a1 is {a1}')
    c=math.sqrt(pow(a1,2)+pow(fy,2))
    print(f'c is {c}')
    A1=math.degrees(math.asin(a1/c))
    print(f'A1 is {A1}')
    B1=math.degrees(math.asin(b1/c))
    print(f'B1 is {B1}')
    # Top triangle
    a2=math.sqrt(pow(c,2)-pow(b2,2))
    print(f'a2 is {a2}')
    A2=math.degrees(math.asin(a2/c))
    print(f'A2 is {A2}')
    B2=math.degrees(math.asin(b2/c))
    print(f'B2 is {B2}')
    coaxra=int(B1+A2)
    print(f'B1+A2 is {coaxra}')
    z=a1
    if a1 > femur+tibia :
        exit
    x, y, z = calculate_line(coax, dega[coaxra], "YZ")
    ax.plot([0,x[1]], [0,y[1]], [rz,z[1]+rz], color='green', label='coax')
    lx=x[1]
    ly=y[1]+coax
    lz=z[1]
    fa=coaxra+90
    print(f'fa is {fa}')
    x, y, z = calculate_line(a2, dega[fa], "YZ")
    ax.plot([lx,x[1]], [ly,y[1]+fy], [lz,z[1]], color='blue', label='Femur + tibia')
    ax.set_xlim(-400, 400)
    ax.set_ylim(-400, 400)
    ax.set_zlim(-100, 400)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')


fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

dega=[]
cc=270
for i in range(361):
        dega.append(cc)
        cc=cc-1
        if cc<1:
          cc=360

fz_slider = Slider(plt.axes([0.1, 0.08, 0.65, 0.03]), 'fZ', -200, 200, valinit=0)
fy_slider = Slider(plt.axes([0.1, 0.04, 0.65, 0.03]), 'fY', -200, 200, valinit=coax)
fx_slider = Slider(plt.axes([0.1, 0.12, 0.65, 0.03]), 'fX', -200, 200, valinit=0)
rh_slider = Slider(plt.axes([0.1, 0.15, 0.65, 0.03]), 'RH', 0, 250, valinit=150)

fz_slider.on_changed(update)
fy_slider.on_changed(update)
fx_slider.on_changed(update)
rh_slider.on_changed(update)

plt.show()

其中dega数组用于修正角度方向。

迁移需求与问题

需将上述模型迁移至Matlab 3D空间,实现通过滑块控制机械足端点位置,并获取对应伺服角度。当前在存储前一段连杆终点作为下一段起点时出现点位对齐问题,对应Python代码行:

lx=x[1]
ly=y[1]+coax
lz=z[1]

已知连杆参数:coax=35、femur=120、tibia=140。


解决方案与Matlab实现

问题根源

Python代码中ly=y[1]+coax属于错误偏移:calculate_line返回的是相对于当前起点的坐标偏移,连杆终点应直接是起点加偏移量,无需额外叠加连杆长度。

完整Matlab代码

% 连杆参数定义
coax = 35;
femur = 120;
tibia = 140;

% 生成角度修正数组dega(与Python逻辑一致)
dega = zeros(1, 361);
cc = 270;
for i = 1:361
    dega(i) = cc;
    cc = cc - 1;
    if cc < 1
        cc = 360;
    end
end

% 创建可视化窗口与3D轴
fig = figure('Position', [100, 100, 800, 600]);
ax = axes('Parent', fig, 'Projection', '3d', 'Position', [0.1, 0.2, 0.8, 0.7]);
xlim(ax, [-400, 400]);
ylim(ax, [-400, 400]);
zlim(ax, [-100, 400]);
xlabel(ax, 'X');
ylabel(ax, 'Y');
zlabel(ax, 'Z');
grid(ax, 'on');

% 创建控制滑块
slider_rh = uicontrol('Parent', fig, 'Style', 'slider', 'Position', [100, 10, 600, 20], ...
    'Min', 0, 'Max', 250, 'Value', 150, 'Callback', @update_plot);
uicontrol('Parent', fig, 'Style', 'text', 'Position', [50, 10, 40, 20], 'String', 'RH');

slider_fx = uicontrol('Parent', fig, 'Style', 'slider', 'Position', [100, 40, 600, 20], ...
    'Min', -200, 'Max', 200, 'Value', 0, 'Callback', @update_plot);
uicontrol('Parent', fig, 'Style', 'text', 'Position', [50, 40, 40, 20], 'String', 'fX');

slider_fy = uicontrol('Parent', fig, 'Style', 'slider', 'Position', [100, 70, 600, 20], ...
    'Min', -200, 'Max', 200, 'Value', coax, 'Callback', @update_plot);
uicontrol('Parent', fig, 'Style', 'text', 'Position', [50, 70, 40, 20], 'String', 'fY');

slider_fz = uicontrol('Parent', fig, 'Style', 'slider', 'Position', [100, 100, 600, 20], ...
    'Min', -200, 'Max', 200, 'Value', 0, 'Callback', @update_plot);
uicontrol('Parent', fig, 'Style', 'text', 'Position', [50, 100, 40, 20], 'String', 'fZ');

% 初始化绘图
update_plot([]);

% 核心更新函数
function update_plot(~)
    % 获取滑块值
    rz = slider_rh.Value;
    fx = slider_fx.Value;
    fy = slider_fy.Value;
    fz = slider_fz.Value;
    
    b1 = fy;
    b2 = coax;
    a1 = rz;
    
    % 清除当前轴内容
    cla(ax);
    
    % 绘制机器人基座框架
    plot3(ax, [0, 0], [0, 0], [0, rz], 'g');
    plot3(ax, [0, 300], [0, 0], [rz, rz], 'g', 'DisplayName', 'robot length');
    plot3(ax, [300, 300], [0, 0], [0, rz], 'g');
    plot3(ax, [0, 0], [0, 150], [rz, rz], 'g', 'DisplayName', 'robot width');
    plot3(ax, [0, 300], [150, 150], [rz, rz], 'g');
    plot3(ax, [300, 300], [150, 0], [rz, rz], 'g');
    legend(ax, 'Location', 'best');
    
    % 逆运动学计算
    c = sqrt(a1^2 + fy^2);
    A1 = rad2deg(asin(a1 / c));
    B1 = rad2deg(asin(b1 / c));
    
    a2 = sqrt(c^2 - b2^2);
    A2 = rad2deg(asin(a2 / c));
    B2 = rad2deg(asin(b2 / c));
    
    coaxra = round(B1 + A2);
    coaxra = mod(coaxra - 1, 360) + 1; % 确保索引在1-360范围内
    
    % 绘制coax连杆:明确起点与终点
    [x_coax, y_coax, z_coax] = calculate_line(coax, dega(coaxra), 'YZ');
    start_coax = [0, 0, rz];
    end_coax = start_coax + [x_coax(2), y_coax(2), z_coax(2)];
    plot3(ax, [start_coax(1), end_coax(1)], ...
        [start_coax(2), end_coax(2)], ...
        [start_coax(3), end_coax(3)], 'g', 'DisplayName', 'coax');
    
    % 绘制femur+tibia连杆:以coax终点为起点
    fa = coaxra + 90;
    fa = mod(fa - 1, 360) + 1; % 确保索引合法
    [x_ft, y_ft, z_ft] = calculate_line(a2, dega(fa), 'YZ');
    start_ft = end_coax;
    end_ft = start_ft + [x_ft(2), y_ft(2), z_ft(2)];
    plot3(ax, [start_ft(1), end_ft(1)], ...
        [start_ft(2), end_ft(2)], ...
        [start_ft(3), end_ft(3)], 'b', 'DisplayName', 'Femur + tibia');
    
    % 输出伺服角度(可根据需求调整输出位置)
    disp(['Coax伺服角度: ', num2str(dega(coaxra)), '°']);
    disp(['Femur伺服角度: ', num2str(dega(fa)), '°']);
    
    % 重置轴范围
    xlim(ax, [-400, 400]);
    ylim(ax, [-400, 400]);
    zlim(ax, [-100, 400]);
end

% 坐标计算函数(与Python逻辑一致,返回相对偏移)
function [x, y, z] = calculate_line(length, angle, axis)
    angle_rad = deg2rad(angle);
    x = [0, 0];
    y = [0, 0];
    z = [0, 0];
    
    switch axis
        case 'XY'
            x(2) = length * cos(angle_rad);
            y(2) = length * sin(angle_rad);
        case 'XZ'
            x(2) = length * cos(angle_rad);
            z(2) = length * sin(angle_rad);
        case 'YZ'
            y(2) = length * cos(angle_rad);
            z(2) = length * sin(angle_rad);
    end
end

关键修正点

  1. 连杆坐标传递逻辑:直接将前一段连杆的终点坐标作为下一段的起点,不再添加额外偏移,确保点位完全对齐。
  2. 角度索引合法性:使用mod运算确保角度数组索引始终在1-360范围内,避免越界错误。
  3. 明确坐标关系:区分起点坐标与相对偏移量,绘图时通过起点加偏移计算终点,逻辑更清晰。

内容的提问来源于stack exchange,提问作者Fulcrum Mason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:24:59