4自由度机械臂正逆解公式推导与代码实现

6 篇文章 0 订阅
5 篇文章 6 订阅

视频链接: 四自由度机械臂逆解抓取(含代码)_哔哩哔哩_bilibili

 

 

 

 

代码

import math

P = 7.5
A1 = 12.1
A2 = 8.2
A3 = 8.2
A4 = 18.5
MAX_LEN = A2+A3+A4
MAX_HIGH = A1+A2+A3+A4

def cos(degree):
    return math.cos(math.radians(degree))

def sin(degree):
    return math.sin(math.radians(degree))


def atan2(v1,v2):
    rad=math.atan2(v1,v2)
    return math.degrees(rad)


def _j_degree_convert(joint,j_or_deg):
    # 将j1-j4和机械臂的角度表达互换
    if joint == 1:
        res = j_or_deg
    elif joint == 2 or joint == 3 or joint == 4:
        res = 90-j_or_deg
    else:
        # 只适用于1-4关节
        raise ValueError
    return res

def _valid_degree(joint,degree):
    if 0 <= degree <= 180:
        return True

    else:
        print('joint {} is invalid degree {}'.format(joint,degree))
        return False



def _valid_j(joint,j):
    if j is None:
        return False
    degree = _j_degree_convert(joint,j)
    if 0 <= degree <= 180:
        return True
    else:
        print('joint {} is invalid j:{} degree {}'.format(joint,j,degree))
        return False

def _out_of_range(lengh,height):
    if height>MAX_HIGH:
        print('高度 {} 超过界限 {}'.format(height,MAX_HIGH))
        return True
    if lengh > MAX_LEN:
        print('投影长度 {} 超过界限 {}'.format(lengh,MAX_LEN))
        return True
    return False


def _calculate_j1(x,y,z):
    length=round(math.sqrt(pow((y+P),2)+pow(x,2)),2)

    if length ==0:
        j1=0 #可以是任意数
    else:
        j1=atan2((y+P),x)
    hight = z
    return j1,length,hight

def _calculate_j3(L, H):
    cos3 = (L**2 + H**2 - A2**2 - A3**2)/(2*A2*A3)
    # cos3=(pow(L,2)+pow(H,2))-(pow(A2,2)+pow(A3,2)/2*A2*A3)
    if (cos3**2>1):
        return None
    sin3=math.sqrt(1-cos3**2)
    j3=atan2(sin3,cos3)
    return j3


def _calculate_j2(L, H, j3):
    K1 = A2 + A3*cos(j3)
    K2 = A3*sin(j3)
    w = atan2(K2,K1)
    j2 = atan2(L,H)-w
    return j2

def _calculate_j4(j2, j3, alpha):
    j4 = alpha - j2 - j3
    return j4



def _xyz_alpha_to_j123(x,y,z,alpha):
    valid = False
    j1, j2, j3, j4 = None, None, None, None
    j1, length, height = _calculate_j1(x,y,z)
    if _valid_j(1,j1) and not _out_of_range(length,height):
        L = length - A4 * sin(alpha)
        H = height - A4 * cos(alpha) - A1
        j3 = _calculate_j3(L, H)
        if _valid_j(3,j3):
            j2 = _calculate_j2(L, H, j3)
            if _valid_j(2,j2):
                j4 = _calculate_j4(j2, j3, alpha)
                if _valid_j(4,j4):
                    valid = True
    return valid, j1, j2, j3, j4


def _xyz_to_j123(x,y,z, alpha=180):
    MIN_ALPHA = 90 # j2+j3+j4 min value, 最后一个joint不向后仰
    valid = False
    j1, j2, j3, j4 = None, None, None, None
    while alpha >= MIN_ALPHA and not valid:
        valid, j1, j2, j3, j4 = _xyz_alpha_to_j123(x,y,z,alpha)
        if not valid:
            alpha -= 1
    return valid, j1, j2, j3, j4



def backward_kinematics(x, y, z, alpha=180):
    x=float(x)
    y=float(y)
    z=float(z)
    print('x:{} y:{} z:{} alpha:{}'.format(x,y,z,alpha))

    if z<0:
        print('z 不能小于0')
        raise ValueError
    if y<0:
        print('y 不能小于0')
        raise ValueError


    valid, j1, j2, j3, j4 = _xyz_to_j123(x,y,z, alpha)
    deg1, deg2, deg3, deg4 = None, None, None, None
    if valid:
        deg1 = round(_j_degree_convert(1,j1),2)
        deg2 = round(_j_degree_convert(2,j2),2)
        deg3 = round(_j_degree_convert(3,j3),2)
        deg4 = round(_j_degree_convert(4,j4),2)

    print('valid:{},deg1:{},deg2:{},deg3:{},deg4:{}'.format(valid,deg1,deg2,deg3,deg4))
    print('{} [{},{},{},{}]'.format(valid,deg1,deg2,deg3,deg4))

    return valid, deg1, deg2, deg3, deg4


def forward_kinematics(deg1,deg2,deg3,deg4):
    valid = False
    if not _valid_degree(1,deg1) or not _valid_degree(2,deg2) or not _valid_degree(3,deg3) or not _valid_degree(4,deg4):
        return valid,None,None,None
    j1=_j_degree_convert(1,deg1)
    j2=_j_degree_convert(2,deg2)
    j3=_j_degree_convert(3,deg3)
    j4=_j_degree_convert(4,deg4)
    length = A2*sin(j2) + A3*sin(j2+j3) + A4*sin(j2+j3+j4)
    height = A1 + A2*cos(j2) + A3*cos(j2+j3) + A4*cos(j2+j3+j4)
    alpha = j2+j3+j4

    z = round(height,2)
    x = round(length*cos(j1))
    y = round(length*sin(j1)-P)


    # 世界坐标的边界
    if 0<=y and z>=0:
        valid = True

    print('valid:{},x:{},y:{},z:{},lenghth:{},height:{},alpha:{}'.format(valid,x,y,z,round(length,2),round(height,2),alpha))

    return valid,x,y,z



def test_ok(x,y,z):
    valid, deg1, deg2, deg3, deg4=backward_kinematics(x, y, z,alpha=180)
    if valid:
        valid,x1,y1,z1=forward_kinematics(deg1,deg2,deg3,deg4)
        if abs(x1-x)>0.5 or abs(y1-y)>0.5 or abs(z1-z)>0.5:
            print('err')
        else:
            print('ok')


if __name__ == '__main__':
    x = 0
    y = 20
    z = 5
    test_ok(x,y,z)
    print('done')

由于六自由度机械臂的求逆解涉及到较为复杂的数学运算,因此需要一定的数学基础和编程能力。以下是一个简单的 MATLAB 代码示例,仅供参考。 假设六自由度机械臂的DH参数如下: a = [0, 0, 0, 0, 0, 0]; alpha = [-pi/2, pi/2, pi/2, -pi/2, -pi/2, 0]; d = [0, 0, 0.15, 0, 0.2, 0]; theta = [0, 0, 0, 0, 0, 0]; 其中,a、alpha、d、theta 分别表示 DH 参数表中的 a、alpha、d、theta,即连杆长度、连杆扭转角、连杆长度、连杆旋转角。假设当前机械臂末端执行器的位姿为: T = [0.7071, -0.7071, 0, 0.6; 0.7071, 0.7071, 0, 0.4; 0, 0, 1, 0.3; 0, 0, 0, 1]; 则求解六自由度机械臂的逆解可以按照以下步骤进行: 1. 计算关节角 theta1 和 theta6: theta1 = atan2(T(2,4), T(1,4)); theta6 = atan2(sqrt(T(1,3)^2 + T(2,3)^2), T(3,3)); 2. 计算关节角 theta5 和 theta4: c1 = cos(theta1); s1 = sin(theta1); c6 = cos(theta6); s6 = sin(theta6); s5 = -T(1,3)*c1*s6 + T(2,3)*s1*s6 + T(3,3)*c6; theta5 = atan2(sqrt(1-s5^2), s5); c5 = cos(theta5); theta4 = atan2(T(3,2)/(s5*d(5)), -T(3,1)/(s5*d(5))) - theta5; 3. 计算关节角 theta2 和 theta3: c4 = cos(theta4); s4 = sin(theta4); c5 = cos(theta5); s5 = sin(theta5); c6 = cos(theta6); s6 = sin(theta6); R03 = T(1:3,1:3) * [c1*c4*c5-s1*s5, -c1*s4, c1*c4*s5+s1*c5; s1*c4*c5+c1*s5, c1*s4, s1*c4*s5-c1*c5; -s4*c5, -s5, -c4*s5]; P03 = [T(1,4) - d(6)*R03(1,3); T(2,4) - d(6)*R03(2,3); T(3,4) - d(6)*R03(3,3)]; theta2 = atan2(P03(2), P03(1)) - atan2(d(2)*s1, d(1)+d(2)*c1); L = sqrt(P03(1)^2 + P03(2)^2 - d(1)^2 - d(2)^2 - 2*d(1)*d(2)*c1); theta3 = atan2(P03(3), L) - atan2(sqrt(1-(P03(3)/L)^2), P03(3)/L); 4. 输出逆解: theta = [theta1, theta2, theta3, theta4, theta5, theta6]; disp(theta); 完整代码如下:
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值