grbl控制3轴机械臂 原理 实现 (一) 之2D机械臂模拟及实现

参考文章:https://blog.csdn.net/noahzuo/article/details/53908141

 

 

机械臂简介

机械臂是指高精度,多输入多输出、高度非线性、强耦合的复杂系统。因其独特的操作灵活性, 已在工业装配, 安全防爆等领域得到广泛应用。机械臂是一个复杂系统, 存在着参数摄动、外界干扰及未建模动态等不确定性。因而机械臂的建模模型也存在着不确定性,对于不同的任务, 需要规划机械臂关节空间的运动轨迹,从而级联构成末端位姿

这里我们主要讲解臂杆型机械臂,如图

 运动原理

这里我们先从最简单的讲起,二维的机械臂如下图,这里分为L1大臂和L2小臂

那么这二维的机械臂的末端位置由大臂的角度和小臂的角度,以及这两臂的长所决定。

我们先假设大臂靠墙的坐标是(0,0),有了原点,要算L2末端坐标,这里涉及到运动学。

运动学正解(Forward kinematics)

    通过各个关节的角度和臂长算出L2末端的坐标,这叫正解

运动学逆解(Inverse kinematics)

    通过L2末端的坐标,计算出各个关节的角度,这叫逆解

可以通过几何分析来进行FK和IK的解算(当然解算的方式有很多种,比如DH法等等,这里用简单的几何法讲解)

 

几何分析

运动学逆解(Inverse kinematics)

L2的末端有一个活动范围(reachable workspace),当解算IK开始的时候,就需要先确保末端关节在这个活动范围内:

|L1-L2|\leq \sqrt{X^2+Y^2} \leq L1+L2

L2的末端的坐标位置确定之后,L1和L2臂对应的两个关节偏转角度\theta 1\theta 2就可以通过几何方法确定了。

令L2的末端的最终坐标位置为(X,Y),连接首关节和尾关节后,可以分析出最终解应该有两个,这两个解关于直线(0,0)到(X,Y)对称。

最终可以使用余弦定理来计算出最终的\theta 1\theta 2,推导过程如下:

\cos (\theta T) = \frac{X}{\sqrt{X^2+Y^2}}
因此有:

\theta T = \arccos (\frac{X}{\sqrt{X^2+Y^2}})


余弦定理:


余弦定理:

A^2 = B^2 + C^2 - 2BC\cos(\alpha )

根据余弦定理,将值代入公式得

L2^2 = L1^2 + (\sqrt{X^2 + Y^2})^2 - 2L1\sqrt{X^2 + Y^2}\cos(\theta 1-\theta T)

 

2L1\sqrt{X^2+Y^2} \cos(\theta 1 - \theta T) = L1^2 + X^2 + Y^2 - L2^2

 

\cos (\theta1 - \theta T) = \frac{L1^2 + X^2 + Y^2 - L2^2}{2L1 \sqrt{X^2+Y^2}}

 

\theta1 = \arccos( \frac{L1^2 + X^2 + Y^2 - L2^2}{2L1 \sqrt{X^2+Y^2}}) + \theta T


根据余弦定理:

\cos(180 - \theta2) = - \cos(\theta2) = \frac{L1^2 + L2^2 - X^2 - Y^2}{2L1L2}


有:

\theta2 = \arccos(\frac{X^2 + Y^2 - L1^2 - L2^2}{2L1L2})

 

这样得到了关节旋转角度\theta 1\theta 2,注意的是cos函数是偶函数,因此需要考虑到±θ的情况。

 

运动学正解(Forward kinematics)

x1,x2,y1,y2分别是蓝色线段部分

由于x1和x2是平行的,所以L1和x1所成角度,和L1和x2所成角度相同,所以有

\theta3 = 90 - \theta1

根据三角函数:

x1 = \cos(\theta 1) L1

x2 = \sin(\theta3 + \theta2)L2

y1 = \sin(\theta1)L1

y2 = \cos(\theta3 + \theta2)L2

X = x1 + x2         代入上式得          X = \cos(\theta 1) L1 + \sin(\theta3 + \theta2)L2 

 

Y = y1 + y2          代入上式得          Y = \sin(\theta1)L1 + \cos(\theta3 + \theta2)L2

 

软件模拟实现

根据上面的推导的几何公式,写一个模拟的2d机械臂试试看,软件用的processing。

PVector P = new PVector(20,50);
//Version 1.1-fix coordinate

//坐标轴偏移坐标
float coordsetoffx,coordsetoffy;

//IK运算,大小臂夹角,平面投影直线夹角
float [] IKrst  = new float[3];

//大小臂长度
float bigL = 200,smallL = 200;

class arm
{
  //单臂建模为射线
  //位置,方向,长度,坐标偏移
  PVector position;
  PVector vector;
  float L;
  float coordsetoffx,coordsetoffy;
  
  arm(PVector a,float lengths)
  {
    vector = new PVector(random(-1,1),random(-1,1)).normalize();
    position = a;
    L = lengths;
    coordsetoffx = 0;
    coordsetoffy = 0;
  }
  
  arm(PVector a,float lengths,float cx,float cy)
  {
    vector = new PVector(random(-1,1),random(-1,1)).normalize();
    position = a;
    L = lengths;
    coordsetoffx = cx;
    coordsetoffy = cy;
    
  }
  
  //设置方向向量
  void setVector(PVector a)
  {
    vector = a.normalize();
  }
  
  //设置位置
  void setPosition(PVector a)
  {
    position = a;
  }
  
  //获取臂末端位置
  PVector getLPosition()
  { 

    return PVector.add(position,PVector.mult(vector,L));
    
  }
  //绘制臂
  void display()
  {
    PVector temp = PVector.mult(vector,L);
    line(coordsetoffx+position.x,coordsetoffy+position.y,coordsetoffx+position.x+temp.x,coordsetoffy+position.y+temp.y);

  }
  
  

}

//向量坐标变换,将y值翻转
PVector tranPvector(PVector a)
{
  //return new PVector(a.x,-a.y,a.z);
  return new PVector(a.x,-a.y);
}


//IK
float [] IK(float x,float y,float L1,float L2)
{
  //依次是平面直线夹角,大臂夹角,小臂夹角
  float ctaT;
  float cta1;
  float cta2;
  
  float [] ctasuzu  = new float[3];
  
  ctaT = acos(x/sqrt(x*x+y*y));
  //如果坐标0以下翻转角度加减
  if(y < 0)
  {
    ctaT = -ctaT;
  }
  
  cta1 = acos((L1*L1+x*x+y*y-L2*L2)/(2*L1*sqrt(x*x+y*y)))+ctaT;
  cta2 = acos((x*x+y*y-L1*L1-L2*L2)/(2*L1*L2));
  
  ctasuzu[0] = ctaT;
  ctasuzu[1] = cta1;
  ctasuzu[2] = cta2;
  
  return ctasuzu;
  
  
}




//声明arm类的2个变量
arm arm1,arm2,arm3;

void setup()
{
  size(700,700);
  //坐标偏移取窗口中心
  coordsetoffx = width/2;
  coordsetoffy = height/2;
  
  //大臂位置,长度,坐标偏移,
  arm1 = new arm(new PVector(0,0),bigL,coordsetoffx,coordsetoffy);
  //方向
  arm1.setVector(tranPvector(new PVector(0.5,1)));
  
  //将大臂的末端位置给小臂,臂长,坐标偏移
  arm2 = new arm(arm1.getLPosition(),smallL,coordsetoffx,coordsetoffy);

  //knift head
  arm3 = new arm(arm2.getLPosition(),20,coordsetoffx,coordsetoffy);

  background(255);
}

void draw()
{
    background(255);
  
    //映射鼠标到坐标系
    IKrst = IK(map(mouseX,0,width,-width/2,width/2),map(mouseY,height,0,-height/2,height/2),bigL,smallL);
    
    println("position: "+map(mouseX,0,width,-width/2,width/2)+" "+map(mouseY,height,0,-height/2,height/2));
    println("C: "+degrees(IKrst[0])+" "+degrees(IKrst[1])+" "+degrees(IKrst[2])+" ");
    //println("arm2:"+arm2.getLPosition().x,arm2.getLPosition().y);
    //println("arm1:"+arm1.getLPosition().x,arm1.getLPosition().y);
    
    
    float xx = cos(IKrst[1]);
    float yy = sin(IKrst[1]);
    
    float xx2 = cos((IKrst[1]-IKrst[2]));
    float yy2 = sin((IKrst[1]-IKrst[2]));
    
    
    arm1.setVector(tranPvector(new PVector(xx,yy)));
    
    arm2.setPosition(arm1.getLPosition());
    arm2.setVector(tranPvector(new PVector(xx2,yy2)));
  
    arm3.setPosition(arm2.getLPosition());
    arm3.setVector(tranPvector(new PVector(xx2,yy2)));
  
    stroke(0);
    arm1.display();
    arm2.display();
    stroke(255,0,0);
    arm3.display();
    
    noStroke();
    fill(0,128,0);
    ellipse(coordsetoffx+arm2.getLPosition().x,coordsetoffy+arm2.getLPosition().y,10,10);
    
    fill(255,0,0);
    ellipse(coordsetoffx+arm3.getLPosition().x,coordsetoffy+arm3.getLPosition().y,10,10);


  
}

void mousePressed()
{


}

实现效果

 

2维的机械臂运动学原理知道了,接下来讲讲3维的3轴机械臂的运动学正反解。

 

第二篇:grbl控制3轴机械臂 原理 实现 (二) 之3D机械臂模拟及实现

 

 

  • 13
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值