eason603 2023-05-12 01:32 采纳率: 0%
浏览 31

6轴机械臂逆解,Pz无法为负

我使用python进行一个六轴机械臂的运动学逆解,在进行J2和J3的分析时,为了消除未知数,将具有pz的公式进行平方,虽然消除了未知数,但导致pz将强制变成正值,如果pz為負,机械臂无法判断,如pz = -10会被改为10。

代码是依照台大林沛群教授的机器人学线上课程撰写的:P5連結(例題) P8連結(詳細算法過程)

計算theta3的代碼:

eq0 = ma.sqrt(px**2+py**2) - a1
eq2 = pz
eqa = 2*(-a3)*a2 
eqb = 2*d4 * a2 
#eq0 = 435.76 - a1 (這裡是例題的數字
#eq2 = 188.6
#化簡常數
eqc = - (((eq0**2)+(eq2**2)) -(a3 **2 + d4**2 + a2**2))  
#這裡eq2 = pz ,在eq2被平方後pz負號就被強制消除了
print(eqc)
equ = 2 * ma.atan2((eqb-ma.sqrt(eqb**2+eqa**2-eqc**2)),(eqa+eqc)) *57.3
theta3 = equ

計算theta2的代碼:

f1 = a3*ma.cos(theta3 * dtr) + d4*ma.sin(alpha3*dtr) * ma.sin(theta3*dtr) +a2
f2 = a3*ma.cos(alpha2*dtr) * ma.sin(theta3 * dtr) - d4*ma.sin(alpha3 * dtr) * ma.cos(alpha2 *dtr) * ma.cos(theta3 * dtr) -d4*sin(alpha2 * dtr)*ma.cos(alpha3*dtr)-d3*ma.sin(alpha2*dtr)
g1 = eq0
eqc = eq0
eqa = f1
eqb = -f2
equ = 2 * ma.atan2((eqb-ma.sqrt(abs(eqb**2+eqa**2-eqc**2))),(eqa+eqc)) *57.3
theta2 = equ

現在的結果是:J1、J4~6正確,J2、J3無法判斷Z軸正負,因此px、py以及最終夾爪姿態都是正確的,僅有當pz為負時會被強制判斷為正

目前嘗試的解決方法:
1.使用solve直接解多項式,但效果不好,跑了1分鐘才出來結果,而且不一定正確
2.直接將常數項補上-pz,但會導致等式不成立
# 定義變數
theta2, theta3 = symbols('theta2 theta3')
# 定義方程
eq1 = -40*sp.cos(theta2*theta3) - 338*sp.sin(theta2*theta3*dtr) + 340*sp.cos(theta2) - 465.79
eq2 = 40*sp.sin(theta2*theta3) - 338*sp.cos(theta2*theta3) - 340*sp.sin(theta2) - 188.6
# 求解方程組
solutions = solve((eq1, eq2), (theta2, theta3))
print(solutions)
我希望能完成的是修改J2 J3的計算公式或是化簡方式使pz的負號不會被消除
以下是PPT中的過程:

img

主要是這張圖中的Eq2平方 如果pz是-188.6會被變為正值:

img

img

完整代碼:
'''
快速導覽:
21~73行:基礎變量定義,包含機械臂基礎DH參數以及,旋轉矩陣計算
74~141行:計算旋轉矩陣以及位移矩陣,於137行分離旋轉矩陣,140行分離位移矩陣,141行輸出目標點px,py,pz
170行:計算theta1角度
193~205行:計算theta3角度 (目前問題)
234~241行:計算theta2角度 (目前問題)
259~299行:計算theta4~6角度
301~302行:輸出結果

'''
'''筆記區
1.三個矩陣聯乘不要使用(a,b,c) 要用 (dot(a,b),c) 詳見48~51行
2.使用sympy計算方程式時,不能使用numpy函數如三角函數的np.cos要改成sp.cos
3.Python TypeError: unsupported operand type(s) for -: 'int' and 'function' 代表某函數使用時他還沒創建 順序改一下就好
4.顯示小數:1: print(round(x,3)) , 2:print('%.3f'%x)
5.Numpy矩陣相乘可以直接用 @ 取代 np.dot
6.160行中的theta3計算公式中,後方sqrt中的數字如果Z過小(目前測試),會變成負數無法開根號,所以加了一個abs()改善,目前未發現負面影響
'''

import numpy as np
import math as ma
import sympy as sp 
from sympy import *
from scipy.optimize import fsolve


Pi = 3.14159265358
dtr = Pi/180
theta1 = theta2 = theta3 = theta4 = theta5 = theta6 = 0.0
def map(value, in_min, in_max, out_min, out_max):
    
    return (value - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
# 定义旋转矩阵绕 X 轴旋转的函数 -252.8 -158.5
def rotate_x(theta):
    return np.array([
        [1, 0, 0],
        [0, cos(theta), -sin(theta)],
        [0, sin(theta), cos(theta)]
    ])

# 定义旋转矩阵绕 Z 轴旋转的函数
def rotate_z(theta):
    return np.array([
        [cos(theta), -sin(theta), 0],
        [sin(theta), cos(theta), 0],
        [0, 0, 1]
    ])
# 定义旋转矩阵绕 Y 轴旋转的函数
def rotate_y(theta):
    return np.array([
        [cos(theta), 0, sin(theta),1],
        [0, 1, 0, 1],
        [-sin(theta), 0, cos(theta),1],
        [0, 0, 0, 1]
    ])



DH_table = np.array([[ -90, 0, -90, 90, -90,0],#alpha-1
                     [ -30, 340, -40, 0, 0,0],#a-1      35 146 52 0 0
                     [0, 0, 0, 338, 0, 0],#d            0 0 0 260.522 0 0 
                     [theta1, theta2, theta3, theta4, theta5, theta6]])#theta
'''
DH_table = np.array([[ -90, 0, -90, 90, -90,0],#alpha-1
                     [ 35, 200, 52, 0, 0,0],#a-1      35 146->200 52 0 0
                     [0, 0, 0, 260.5, 0, 0],#d            0 0 0 260.522 0 0 ##Lbase高 25.5
                     [theta1, theta2, theta3, theta4, theta5, theta6]])#theta
'''
alpha0 = 0
alpha1, alpha2, alpha3, alpha4, alpha5, alpha6 = DH_table[0]
a1, a2, a3, a4, a5, a6 = DH_table[1]
d1, d2, d3, d4, d5, d6 = DH_table[2]
#---各個目標變數---/*
#桌手XYZ 預設:830 20 330 
W_D_X = 830                                  
W_D_Y = 20 
W_D_Z = 330
#杯桌XYZ 預設:-280 250 62.5 原點:0 0 右上角 292 292 , 185 368
D_C_X = -280
D_C_Y = 250
D_C_Z = 62.5
#夾爪底座離地高度 預設 373
W_0_Z = 373
#夾爪長度 預設 206 (夾爪最後一根 這不會放在DH:151.5)
six_C_Z = 206
#夾爪最終姿態 預設 35 0 (朝下為0 90) (Matlab中z軸為頭)
#lastangleX = map(D_C_Y,0,620,-45,45)
#print(lastangleX)
lastangleX = 35
#lastangleY = map(D_C_X,-400,0,90+45,90-45)
lastangleY = 0
#print(lastangleY)
#---各個目標變數---*/
#桌子對於手臂0的T
W_D = np.array([[1, 0, 0, W_D_X],
                [0, 1, 0, W_D_Y],
                [0, 0, 1, W_D_Z],
                [0, 0, 0, 1]])

#杯子對於桌子0的T
D_C = np.array([[ma.cos(lastangleX * Pi/180),-ma.sin(lastangleX * Pi/180),0,D_C_X],
                [ma.sin(lastangleX * Pi/180),ma.cos(lastangleX * Pi/180),0,D_C_Y],
                [0, 0, 1, D_C_Z],
                [0, 0, 0, 1]])

if lastangleY != 0:
    D_C = D_C @ rotate_y(lastangleY * dtr)

#杯子對於手臂0的T (手臂to桌子to杯子) (前面兩個相乘)
W_C = np.dot(W_D, D_C)

#0對於手臂的T(基本上只有單純的底座高度增加而已)
W_0 = np.array([[1, 0, 0, 0],
                [0, 1, 0, 0],
                [0, 0, 1, W_0_Z],
                [0, 0, 0, 1]])

#杯子對於夾爪(夾爪自己的長度補償)
six_C = np.array([[0 ,0, 1, 0],
                [0, -1, 0, 0],
                [1, 0, 0, six_C_Z],
                [0, 0, 0 ,1]])
#原:0~杯 = 0~手0 * 手0~手6 * 手6~杯 求手0~手6
#轉:手0~手6 = 0~手0(逆) * 0~杯(不逆) * 手6~杯(逆) 
#(手臂的0~6全角度)(非常重要!!)
'''錯誤方式
zero_six_T = np.dot(np.linalg.inv(W_0), W_C , np.linalg.inv(six_C))

print("A:",zero_six_T)
'''

zero_six_T = np.dot(np.dot(np.linalg.inv(W_0), W_C) , np.linalg.inv(six_C))

#print(zero_six_T)
#分離旋轉矩陣R
zero_six_R = zero_six_T[:3, :3]
#print("R:",zero_six_R)
#分離位移矩陣P
zero_six_P= np.array([[zero_six_T[0,3]],[zero_six_T[1,3]],[zero_six_T[2,3]]]) 
print("目標點:",zero_six_P)

#STEP3:找1~6角度!!!!!
#1~3分離
#4對3的T
three_4_T = np.array([[alpha3],
                    [-(d4)*ma.sin(alpha3 * Pi/180)],
                    [d4*ma.cos(alpha3 * Pi/180)],
                    [d4*ma.cos(alpha3 * Pi/180)],
                    [1]])

r = (zero_six_P[0]*zero_six_P[1]*zero_six_P[2])
ax = zero_six_R[0,2]
ay = zero_six_R[1,2]
az = zero_six_R[2,2]
px = zero_six_P[0,0]
py = zero_six_P[1,0]
pz = zero_six_P[2,0]
#print(px,py,pz)
#print ((ma.atan2(py,px)) 
#-ma.atan2(-d2 ,-ma.sqrt( px**2+py**2-d2**2)))
#print(ma.atan2(zero_six_P[1,0],zero_six_P[0,0])-ma.atan2(d3/ma.sqrt(px**2+py**2),ma.sqrt(1-(d3**2/(ma.sqrt(px**2+py**2))**2))))

#print(ma.atan(py/px))
#print("py:",py ,"px:",px)
#print(-ma.atan2(-d2 , ma.sqrt(zero_six_P[0,0]**2+zero_six_P[1,0]**2-d2**2)))
#print(((ma.atan2(py,px))-ma.atan2(d2,ma.sqrt((ma.sqrt(px**2+py**2-d2**2))))))

'''theta1 = (((ma.atan2(py,px))-ma.atan2(d2,ma.sqrt((ma.sqrt(px**2+py**2-d2**2))))) * 57.3)'''
theta1 = ma.atan2(py,px)*57.3
#theta1_2 = (((ma.atan2(py,px))-ma.atan2(d2,-ma.sqrt((ma.sqrt(px**2+py**2-d2**2))))) * 57.3) 0.018 0.274

#k = ((px**2+py**2+ pz**2 - a2**2-a3**2-d3**2-d4**2)/(2*a2))
#print((a3**2+d4**2-k**2))
#theta3 = ((((ma.atan2(a3,d4))- (ma.atan2(k,np.sqrt(abs(a3**2+d4**2-k**2))))))) *57.3 
#print(theta3)
'''print("k:","%.3f"%k)
print("theta3前半","%.3f"%((ma.atan2(a3,d4))))
print("theta3後半","%.3f"%(ma.atan2(k,ma.sqrt(abs(a3**2+d4**2-k**2)))))'''

# 定義變數
#theta2, theta3 = symbols('theta2 theta3')

# 定義方程
eq1 = -40*sp.cos(theta2*theta3) - 338*sp.sin(theta2*theta3*dtr) + 340*sp.cos(theta2) - 465.79
eq2 = 40*sp.sin(theta2*theta3) - 338*sp.cos(theta2*theta3) - 340*sp.sin(theta2) - 188.6

# 求解方程組
#solutions = solve((eq1, eq2), (theta2, theta3))
#print(solutions)


eq0 = ma.sqrt(px**2+py**2) - a1
eq2 = pz
eqa = 2*(-a3)*a2 
eqb = 2*d4 * a2 
#eq0 = 435.76 - a1
#print(eq0)
#eq2 = 188.6
#化簡常數
eqc = - (((eq0**2)+(eq2**2)) -(a3 **2 + d4**2 + a2**2)) #這裡eq2 = pz ,在eq2被平方後pz負號就被強制消除了
print(eqc)

equ = 2 * ma.atan2((eqb-ma.sqrt(eqb**2+eqa**2-eqc**2)),(eqa+eqc)) *57.3
theta3 = equ

#print("eqa:",eqa, "eqb",eqb, "eqc",eqc)
#print(eq0[0]**2+eq0[2]**2)
#print("-a3:",-a3, "d3",d4, "a2",a2)
'''def equations(variables):
    theta2, theta3 = variables
    Eq1 = -40*np.cos(theta2+theta3) - 338*np.sin(theta2+theta3) + 340*np.cos(theta2) - eq0
    Eq2 = 40*np.sin(theta2+theta3) - 338*np.cos(theta2+theta3) - 340*np.sin(theta2) - pz
    return [Eq1, Eq2]

# 初始估计值
initial_guess = [0.0324, 1.4]

# 解方程组
theta2, theta3 = fsolve(equations, initial_guess)

print("theta2 =", theta2)
print("theta3 =", theta3)'''



#theta3 = ((((ma.atan2(a3,d4))- (ma.atan2(k,np.sqrt(abs(a3**2+d4**2-k**2))))))) *57.3 *0.277
#print(theta3)
'''theta2 = (ma.atan2((-a3-a2*ma.cos(theta3*dtr))*pz+(ma.cos(theta1*dtr)*px+ma.sin(theta1*dtr)*py)*(a2*ma.sin(theta3*dtr)-d4)
            ,(-d4+a2*ma.cos(theta3*dtr))*pz-(ma.cos(theta1*dtr)*px+ma.sin(theta1*dtr)*py)*(-a2*ma.cos(theta3*dtr)-a3))*57.3 - (theta3)) #*1.02554'''
'''theta22 = (ma.atan2((-a3-a2*ma.cos(theta32*dtr))*pz+(ma.cos(theta1*dtr)*px+ma.sin(theta1*dtr)*py)*(a2*ma.sin(theta32*dtr)-d4)
            ,(-d4+a2*ma.cos(theta32*dtr))*pz-(ma.cos(theta1*dtr)*px+ma.sin(theta1*dtr)*py)*(-a2*ma.cos(theta32*dtr)-a3))*57.3 -theta32)'''

f1 = a3*ma.cos(theta3 * dtr) + d4*ma.sin(alpha3*dtr) * ma.sin(theta3*dtr) +a2
f2 = a3*ma.cos(alpha2*dtr) * ma.sin(theta3 * dtr) - d4*ma.sin(alpha3 * dtr) * ma.cos(alpha2 *dtr) * ma.cos(theta3 * dtr) -d4*sin(alpha2 * dtr)*ma.cos(alpha3*dtr)-d3*ma.sin(alpha2*dtr)
g1 = eq0
eqc = eq0
eqa = f1
eqb = -f2
equ = 2 * ma.atan2((eqb-ma.sqrt(abs(eqb**2+eqa**2-eqc**2))),(eqa+eqc)) *57.3
theta2 = equ


#print("theta22","%.1f"%theta22)
#theta2 = ma.acos((l1**2+l2**2-l3**2)/(2*l1*l2))
#theta2 = ma.atan(pz/ma.sqrt(px**2+py**2)+ma.acos((l1**2+l3**2-l2**2)/(2*l1*l3))) *57.3
#print("theta2:",'%.3f'%theta2)
#print("theta1:",'%.3f'%theta1)
'''if(theta3>181):
    theta3 = theta3 -360
if(theta4>181):
    theta4 = theta4 -360
if(theta5>181):
    theta5 = theta5 -360
if(theta6>181):
    theta6 = theta6 -360'''


# 读入用户输入的旋转角度
theta1_x = alpha0 * dtr
theta1_z = theta1 * dtr
theta2_x = alpha1 * dtr 
theta2_z = theta2 * dtr
theta3_z = alpha2 * dtr
theta4_z = theta3 * dtr

# 计算旋转矩阵 R
zero_three_R = rotate_x(theta1_x) @ rotate_z(theta1_z) @ rotate_x(theta2_x) @ rotate_z(theta2_z) @ rotate_z(theta3_z) @ rotate_z(theta4_z)

# 输出旋转矩阵 R
'''print("0-6 RotationMatrix = ")
for row in zero_three_R:
    for element in row:
        print("%.3f" % element, end=' ')
    print()'''
    

#print(zero_six_R)
#print("轉換前:\n",zero_three_R)

#----------
zero_three_R = zero_three_R @ rotate_x(-90*dtr) #--4章題目的是轉90前 所以會有點不一樣

zero_three_R = np.float64(zero_three_R)
#print("轉換90後\n:",zero_three_R)

three_six_R = np.linalg.inv(zero_three_R) @ zero_six_R
#print("0-6的R:\n",zero_six_R)
'''print("3-6 RoatationMatrix = ")
for row in three_six_R:
    for element in row:
        print("%.3f" % element, end=' ')
    print()'''

theta5 = ma.atan2(ma.sqrt(three_six_R[2,0]**2 + three_six_R[2,1]**2),three_six_R[2,2]) * 57.3

#print(ma.sqrt(three_six_R[2,0]**2+three_six_R[2,1]**2))
theta4 = ma.atan2((three_six_R[1,2]/ma.cos(theta5*dtr)),(three_six_R[0,2]/ma.cos(theta5*dtr))) *57.3
theta6 = ma.atan2((three_six_R[2,1]/ma.cos(theta5*dtr)),(-three_six_R[2,0]/ma.cos(theta5*dtr))) *57.3

print("theta1:","%.1f"%theta1,"theta2:","%.1f"%theta2,"theta3:","%.1f"%theta3)
print("theta4:","%.1f"%theta4,"theta5:","%.1f"%-theta5,"theta6:","%.1f"%theta6)
#print("theta4A:","%.3f"%(theta4+180),"theta5A:","%.3f"%theta5,"theta6A:","%.3f"%(theta6-180))

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-05-12 12:28
    关注
    不知道你这个问题是否已经解决, 如果还没有解决的话:

    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 修改了问题 5月12日
  • 创建了问题 5月12日

悬赏问题

  • ¥15 抖音登录系统繁忙 无法登录,谁能解决奖励2W
  • ¥15 公司内部的信息化建设应该考哪些证书,学习
  • ¥15 编写泥浆密度在管路中变化,管路瞬变流计算根据上述描述表示泥浆密度沿着管路的长度方向在不断变化,如何来表示泥浆密度随管路流速的变化
  • ¥15 python程序怎么关闭console窗口,仍然保持程序运行
  • ¥15 sap for java
  • ¥15 如何添加系统级别的屏幕边框
  • ¥100 图像处理,如何优化使得清晰
  • ¥15 请求看看这个仿真电路哪里有问题?
  • ¥100 关于python拓展屏使用pyautogui.screenshot无法截图的问题
  • ¥15 有偿求答 无导出权限怎么快速导出企业微信微文档