在设计好六自由度机械臂的控制程序(包含上位机及下位机)后,我们需要通过实验来验证机械臂的精度与可行性。

本篇文章通过设计电路板抓取实验来验证机械臂作业的可行性。严格来说这个实验设计的没有什么科学依据,仅供参考。

一、上位机设计
控制机械臂时,使用由Python编写的上位机(GUI编程使用Python内置的图形开发界面库Tkinter)。

1.GUI界面
共分为三个界面:关节校准界面、主控界面及轨迹点寄存器界面。

我们所使用的六自由度机械臂以开环形式运行,无法获取各关节期望角度与当前实际角度的差值。因此,在机械臂作业前,需对所有关节进行校准。

上位机需同时满足对关节的单独控制及对末端执行器的直接控制,因此设计主控界面。其中,左下方为命令行显示区域。

当机械臂所执行的任务需要定义多个轨迹点时,可将轨迹点的位置坐标与RPY角值储存于该寄存器中。

2.通信协议

前6位为各关节需旋转到的期望角度。第7位用于调节机械臂各关节的旋转速度。第8、9位用于设定运动中加速段的时长与加速度。第10、11位用于设定运动中减速段的时长与减速度。最后1位为判断程序是否出现错误的标识符,若目标点位于可达工作空间内则置为0,下位机执行程序语句。

3.命令说明
注:该部分在资源中的上位机源代码部分中有详细注释,可跳过

Move J。该命令是使机械臂所有的关节一起工作来完成移动,轨迹形状通常不为直线, 而是一个所有关节一起工作的扫动。这是最简单也是最常用的方法。这就是前文中我们分析的线性规划。

off J。这是一个被存储位置的值抵消的联合移动。此移动将应用在“teach new position”按钮上方的存储位置字段中设置的任何存储位置号。

Move L。这将执行一个完美的直线到期望位置。这个程序生成向下位机发送一系列的路径点。

Move A。使得机械臂的轨迹为一圆弧。首先选择“Move A Beg”,并同时设置机械臂的运行速度(示教是设置速度比例)。其次,选择“Move A Mid”,然后示教第二个点。最后选择“Move A End”,并在终点或弧线上标出你想要的轨迹点。命令窗口现在将有 3 行代码,每行对应 3 个点。当一个“Move A Beg”的代码行被执行,程序将自动运行接下来的 2 行代码来计算弧并生成轨迹。如果轨迹无法实现,这一步就无法进行。当所有形成弧的路径点都被传输到下位机的过程中,在执行移动 a 之前会有几秒钟的延迟。

Move C。在空间中3个点确定一个圆,因此,我们同样需要储存三个点的坐标。步骤与Move A相同。

Move SP。在轨迹点寄存器界面中有 16 个可以设置的存储位置。X,Y,Z,Y,P,R,对于你想要执行的任何位置或程序中的多个位置。当你示教时,机械臂将移动到你在寄存器标签上为存储位置所输入的位置。

off SP。使机械臂移动到一个存储位置,然后通过另一个存储位置的值对该位置进行偏移。

Teach SP。这个移动命令将插入 6 行到你的程序中,当执行时将机器人当前位置存储到你选择的轨迹点寄存器中。这使得根据需要填充存储的位置变得更加容易。

二、实验设计
我们设计实验的操作对象为尺寸为3.8cm×2.8cm的电路板,实验中机械臂的运动路线如下图所示。

其中,实线方框表示电路板拿取区域,虚线方框表示电路板放置区域。所有电路板均位于基坐标系的平面上,圆弧上各区域间相距22.5°,实际摆放如下图所示。

实验过程中,机械臂需要沿着圆弧轨迹将电路板从拿取区域移动至放置区域,同时,最后一块电路板需要在移动过程中旋转90°。

生成轨迹所需要的目标点按通信协议储存于上位机的指令显示区域(位于主控界面左下角),如下图所示。

三、机械臂夹爪控制程序
机械臂夹爪的控制选用了之前学习过的正点原子开发板舵机型号为S3010,是之前搞智能车竞赛剩下的,该舵机的转角与高电平的脉宽有关,黑线接地,红线接电源(5V),白线为控制线。

int main(void)
{ 
    u8 key;              //保存键值
    u16 pwmval=1945;     //pwm比较值初始化,此时夹爪张开到最大角度
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    delay_init(168);  //初始化延时函数
    uart_init(115200);//串口波特率115200
     TIM14_PWM_Init(2000-1,840-1);    //84M/840=0.1Mhz的技术频率,重装载值为2000,所以pwm频率为50hz,周期为20ms
    KEY_Init();       //初始化与按键连接的硬件接口

   while(1) //根据按键改变夹爪开闭状态
    {
         delay_ms(10);    
        key=KEY_Scan(1);        //得到键值
        if(key)
        {
            switch(key)
            {
                case KEY0_PRES:       //按下按键0,夹爪闭合
                    pwmval=pwmval+1; //递增,通过改变加数,改变夹爪速度
                    if(pwmval>1945)  //该限值由夹爪机械结构决定
                    pwmval=1945;
                    break;
                case KEY1_PRES:       //按下按键1,夹爪张开
                    pwmval=pwmval-1; //递减,通过改变减数,改变夹爪速度
                    if(pwmval<1875)//该限值由夹爪机械结构决定
                    pwmval=1875;
                    break;
            }
        }
        TIM_SetCompare1(TIM14,pwmval);    //改变占空比
    }
}