机械臂运动学逆解

机械臂正逆解

由于贫穷的关系,只得在淘宝上购买“玩具”机械臂进行研究,这是下面这货:
2022年2月更:之前的这个求解方式对于姿态的约束是有一些问题的,此课程包含了修正后的3、4自由度机械臂的逆解推导与源码,有兴趣的可以了解一下
在这里插入图片描述
相信小伙伴都在淘宝上买了这个手臂来玩耍,但是这手跟工业传统的6轴机械臂那差了不是一点半点。找寻了半天也没有找到现成的DH模型和运动学逆解。所有就自己使用几何法建立了模型并给出运动学逆解。最后的控制效果可以观看视频:

机械臂功能演示视频

下面是几何解过程,并附上C/C++的程序

经过我的分析,这个机械臂可以简化成一个4自由度的机械臂(夹子和夹子上的那两个舵机对运动学逆解无关),如下图:

在这里插入图片描述
画出几何示意图:
在这里插入图片描述
这里的j0、j1、j2、j3是指4个舵机转动的角度,L1、L2、L3指三节手臂的长度。末端执行器(夹子)中心的坐标为逆解目标 (x,y,z)

这里值得注意的一点就是该手臂与工业6自由度的手有很大区别,工业6自由度的手的逆解目标是末端执行器的姿态加坐标,即一个齐次变换矩阵。而我们这个手按照这样来几乎很多位置都是没有解的,所有我们就剔除姿态,只保留坐标,即我们只要求我们的夹子到达这个坐标,而不需要夹子是以何种姿态到达这个坐标的。所有我们的逆解目标仅仅是个坐标而已。

这样我们容易得到正向解结果如下:

// 根据舵机角度正向解出目标坐标
	x = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*cos(j0);
	y = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*sin(j0);
	z = L1 * cos(j1) + L2 * cos(j1 + j2) + L3 * cos(j1 + j2 + j3);

这里我们可以看出,我们的输入是j0、j1、j2、j3这四个舵机转动的角度,而我们的目标只是一个 三维坐标(x,y,z)
逆解就是输入坐标(x,y,z),然后求j0、j1、j2、j3,但是我们逆向求解的时候就可能会出现多组解
(未知数的个数4大于方程的个数3)。这样的话我们就只能先确定一个未知数的取值,然后才能对方程进行求解。

底座舵机j0的最好算:

j0 = atan2(y, x);

这里我采取的是先确定j1的值,然后再求解方程(这里方程的推导我就不写啦,直接上代码,代码里就是我解出来的结果)。但是我们所确定的这个j1的值不一定能求出解,也可能求出几组解。所有我们就将j1舵机所能到达的角度都取一遍,保证能求出更多的解。

	for (j1 = -90; j1 < 90; j1++)//先确定j1的值,并且把j1从-90°到90°都取一遍,算出所有有可能的解
	{
		j1 *= RAD2ANG;//弧度转换
		j3 = acos((pow(a, 2) + pow(b, 2) + pow(L1, 2) - pow(L2, 2) - pow(L3, 2) - 2 * a*L1*sin(j1) - 2 * b*L1*cos(j1)) / (2 * L2*L3));
		//确定j1的角度后,就可以求出j3的角度。
		m = L2 * sin(j1) + L3 * sin(j1)*cos(j3) + L3 * cos(j1)*sin(j3);
		n = L2 * cos(j1) + L3 * cos(j1)*cos(j3) - L3 * sin(j1)*sin(j3);
		t = a - L1 * sin(j1);
		p = pow(pow(n, 2) + pow(m, 2), 0.5);
		q = asin(m / p);
		j2 = asin(t / p) - q;
		//接着就可以求出j2的角度。
		//求出4个角度后,我们先验算一遍这4个角度求出的值(x1,y1,z1)和我们的目标坐标(x,y,z)是否一致
		x1 = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*cos(j0);
		y1 = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*sin(j0);
		z1 = L1 * cos(j1) + L2 * cos(j1 + j2) + L3 * cos(j1 + j2 + j3);
		j1 = ANG2RAD(j1);
		j2 = ANG2RAD(j2);
		j3 = ANG2RAD(j3);
		//输出误差小于1cm的解,并输出该解的正向解目标
		if(x1<(x+1) && x1 > (x-1) && y1<(y + 1) && y1 >(y - 1) && z1<(z + 1) && z1 >(z - 1))
		{
			printf("j1:%f,j2:%f,j3:%f,x:%f,y:%f,z:%f\r\n", j1, j2, j3, x1, y1, z1);
		}
	}

可执行的完整C++代码如下(直接复制这个用,上面的代码是过程讲解):

#include "pch.h"
#include <iostream>
#include <stdio.h>
#include <math.h>

#define RAD2ANG (3.1415926535898/180.0)
#define ANG2RAD(N) ( (N) * (180.0/3.1415926535898) )
void inverseKinematics(double x, double y, double z);

int main()
{
	inverseKinematics(0, 30, 0);//逆解目标为(0,30,0)这个坐标

}

void inverseKinematics(double x, double y, double z)
{
	double a, b, c; //临时变量
	double L1 = 10, L2 = 11, L3 = 14;//3节手臂的长度
	double m, n, t, q, p;//临时变量
	double j1, j2, j3, j0;//4个舵机的旋转角度
	double x1, y1, z1;//逆解后正解算出来的值,看是否与逆解值相等
	char i = 0;
	j0 = atan2(y, x);
	a = x / cos(j0);
	if (x == 0) a = y; //如果x为0,需要交换x,y
	b = z;

	for (j1 = -90; j1 < 90; j1++)
	{
		j1 *= RAD2ANG;
		j3 = acos((pow(a, 2) + pow(b, 2) + pow(L1, 2) - pow(L2, 2) - pow(L3, 2) - 2 * a*L1*sin(j1) - 2 * b*L1*cos(j1)) / (2 * L2*L3));
		//if (abs(ANG2RAD(j3)) >= 135) { j1 = ANG2RAD(j1); continue; }
		m = L2 * sin(j1) + L3 * sin(j1)*cos(j3) + L3 * cos(j1)*sin(j3);
		n = L2 * cos(j1) + L3 * cos(j1)*cos(j3) - L3 * sin(j1)*sin(j3);
		t = a - L1 * sin(j1);
		p = pow(pow(n, 2) + pow(m, 2), 0.5);
		q = asin(m / p);
		j2 = asin(t / p) - q;
		//if (abs(ANG2RAD(j2)) >= 135) { j1 = ANG2RAD(j1); continue; }
		/***************计算正解然后与目标解对比,看解是否正确**************/
		x1 = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*cos(j0);
		y1 = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*sin(j0);
		z1 = L1 * cos(j1) + L2 * cos(j1 + j2) + L3 * cos(j1 + j2 + j3);
		j1 = ANG2RAD(j1);
		j2 = ANG2RAD(j2);
		j3 = ANG2RAD(j3);
		if (x1<(x + 1) && x1 >(x - 1) && y1<(y + 1) && y1 >(y - 1) && z1<(z + 1) && z1 >(z - 1))
		{
			printf("j0:%f,j1:%f,j2:%f,j3:%f,x:%f,y:%f,z:%f\r\n", ANG2RAD(j0), j1, j2, j3, x1, y1, z1);
			i = 1;
		}
	}
	for (j1 = -90; j1 < 90; j1++)//这个循环是为了求解另一组解,j2 = asin(t / p) - q;j2 = -(asin(t / p) - q);多了个负号
	{
		j1 *= RAD2ANG;
		j3 = acos((pow(a, 2) + pow(b, 2) + pow(L1, 2) - pow(L2, 2) - pow(L3, 2) - 2 * a*L1*sin(j1) - 2 * b*L1*cos(j1)) / (2 * L2*L3));
		//if (abs(ANG2RAD(j3)) >= 135) { j1 = ANG2RAD(j1); continue; }
		m = L2 * sin(j1) + L3 * sin(j1)*cos(j3) + L3 * cos(j1)*sin(j3);
		n = L2 * cos(j1) + L3 * cos(j1)*cos(j3) - L3 * sin(j1)*sin(j3);
		t = a - L1 * sin(j1);
		p = pow(pow(n, 2) + pow(m, 2), 0.5);
		q = asin(m / p);
		j2 = -(asin(t / p) - q);
		//if (abs(ANG2RAD(j2)) >= 135) { j1 = ANG2RAD(j1); continue; }
		x1 = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*cos(j0);
		y1 = (L1 * sin(j1) + L2 * sin(j1 + j2) + L3 * sin(j1 + j2 + j3))*sin(j0);
		z1 = L1 * cos(j1) + L2 * cos(j1 + j2) + L3 * cos(j1 + j2 + j3);
		j1 = ANG2RAD(j1);
		j2 = ANG2RAD(j2);
		j3 = ANG2RAD(j3);
		if (x1<(x + 1) && x1 >(x - 1) && y1<(y + 1) && y1 >(y - 1) && z1<(z + 1) && z1 >(z - 1))
		{
			printf("j0:%f,j1:%f,j2:%f,j3:%f,x:%f,y:%f,z:%f\r\n", ANG2RAD(j0), j1, j2, j3, x1, y1, z1);
			i = 1;
		}
	}

	if (i == 0)printf("无解");

}

输出结果如下图:
在这里插入图片描述

然后我们就可以根据我们的需求选择我们的解,如果只是简单抓取地面上的东西,就选择夹子向下且最接近垂直的那个解即j3最接近90的那个解,这个解最适合夹取地面上的东西。如果是像视频中倒水一样,就得选择夹子为水平的解,具体是个什么约束关系你们可以自己推一推。反正你可以自由选择解。
2022年2月更:之前的这个求解方式对于姿态的约束是有一些问题的,此课程包含了修正后的3、4自由度机械臂的逆解推导与源码,有兴趣的可以了解一下

最后大家有不懂或者有更好建议的请加我

机械臂基础入门图文教程1
机械臂基础入门图文教程2
机械臂基础入门图文教程3
控制该机械臂的视频教程与源码、包括机械臂系统从上到下的梳理、机械臂的硬件、通讯与控制

QQ:965295412 WX:15310294950

### 三自由度机械运动学 对于三自由度(3DOF)机械,在MATLAB中实现运动学(IK)求通常涉及定义连杆参数(DH参数),建立正向运动学模型,以及通过或数值决IK问题。 #### DH 参数设置 为了描述机械各关节之间的相对位置关系,采用Denavit-Hartenberg (DH) 参数表示。假设给定一个简单的平面内操作的3DOF机械,则可以设定相应的DH参数表[^1]: | Link | α<sub>i-1</sub> | a<sub>i-1</sub>| d<sub>i</sub> | θ<sub>i</sub>(Joint Variable) | |--|--------------------------------| | 1 | π/2 | 0 | L1 | q1 | | 2 | 0 | 0 | L2 | q2 | | 3 | 0 | 0 | L3 | q3 | 其中L1, L2 和 L3 是各个连杆长度;q1,q2 及 q3 表示三个旋转关节的角度变量。 #### 正向运动学方程构建 利用上述DH参数可得末端执行器相对于基座坐标系的姿态T矩阵表达式为: \[ T_0^e(q)=\prod_{i=1}^{n}{A_i}(q)\] 这里\( A_i \)代表第 i 条连杆对应的齐次变换矩阵。 #### 运动学 考虑到此特定类型的3DOF机械具有较简单几何特性,可以直接推导出闭合形式的决方案。设目标位姿已知,即期望的位置(x,y,z)和方向姿态(Roll,Pitch,Yaw), 则可通过三角函数计算得到所需关节角度值。 下面是具体的 MATLAB 实现代码片段用于展示如何完成这一过程: ```matlab function [theta1, theta2, theta3] = ik_solver_3dof(x_desired, y_desired, z_desired) % 输入: 目标点的空间直角坐标[x_desired; y_desired;z_desired] % 输出: 各个关节转角[theta1; theta2; theta3] global l1 l2 l3 % 定义全局变量存储连杆长度 r_squared = x_desired.^2 + y_desired.^2; phi = atan2(y_desired,x_desired); rho = sqrt(r_squared); if rho < abs(l1-l2+l3) || rho > (l1+l2+l3) error('Target position out of reach'); end cos_theta3 = (rho^2-(l1)^2-(l2+l3)^2)/(2*l1*(l2+l3)); sin_theta3 = sqrt(1-cos_theta3^2); theta3 = pi - atan2(sin_theta3 , cos_theta3 ); alpha = acos((l1^2+(l2+l3)^2-rho^2)/(2*l1*(l2+l3))); beta = asin(l3*sin(theta3)/sqrt(l2^2+2*l2*l3*cos(alpha)+l3^2)); theta2 = -(pi-alpha-beta-theta3); theta1 = phi; disp(['The joint angles are:', num2str([theta1*radtodeg, theta2*radtodeg, theta3*radtodeg])]); end ``` 这段程序实现了从笛卡尔空间到关节空间转换的功能,并考虑到了工作范围限制条件下的错误处理机制。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值