基于STM32与TB6600的机械臂项目(代码开源)

        前言:本文为手把手教学STM32的机械臂项目——Robot Arm,本次项目采用的是STM32作为MCU。该机械臂的基础模型为国外开源项目,诸多前辈经过长时间的验证与改进,其机械臂精度可以满足日常需求。本项目机械臂为三自由度机械臂,42步进电机搭配TB6600驱动器作为动力支撑。整体项目框架具有极高的可拓展性,方便后期实现视觉抓取等高级嵌入式开发应用。 机械臂的控制选用JDY-31蓝牙控制,结合手机上位机APP进行联动。(文末有代码与3D打印件开源!

        实验硬件:STM32F103ZET6;TB6600驱动器;42步进电机;JDY-31蓝牙模块;5V步进电机;ULN2003驱动板;机械臂3D打印件

        硬件实物图:

        效果图:

一、机械臂简介

        机械臂是机械人技术领域中得到最广泛实际应用的自动化机械装置,在工业制造、医学治疗、娱乐服务、军事、半导体制造以及太空探索等领域都能见到它的身影。尽管它们的形态各有不同,但它们都有一个共同的特点,就是能够接受指令,精确地定位到三维(或二维)空间上的某一点进行作业。机械臂是指高精度,多输入多输出、高度非线性、强耦合的复杂系统。因其独特的操作灵活性,已在工业装配、安全防爆等领域得到广泛应用。

        本项目的机械臂目前为被动控制方案,需要使用手机蓝牙APP作为上位机,人为控制抓取目标物。考虑到目前设计的机械臂已拥有较高的机械精度,后续可以附加树莓派等开发板进行视觉抓取开发。

二、42步进电机与TB6600驱动器

2.1 42步进电机

        42步进电机是指安装机座尺寸是42mm×42mm的步进电机,又叫NEMA 17步进电机(这里的NEMA是National Electrical Manufacturers Association的缩写,美国电气制造商协会是美国最大的电气设备制造商协会),如下图所示,相同机座尺寸的步进电机又有不同长度和不同绕组参数的型号,一般相同机座尺寸的情况下,步进电机越长,定子上能够绕下的绕组就越多,电机的输出力矩就越大。

42 57 86步进电机的主要区别是什么(即42 57 86的意义是什么)?

答:42 57 86步进电机的区别主要是步进电机的机座不同,尺寸分别是42×42mm、57×57mm、86×86mm,一般来说步进电机的机座尺寸越大,电机的静力矩就越大,电机运行时的转矩就越大,电机能够承受的负载就越大。

        本项目中所使用的为四线二相42步进电机,步距角是1.8度,在无细分的情况下转一圈走200步,360/1.8=200。切记:42这个数字的含义仅与电机的尺寸有关。而电机步距角细分程度只与电机驱动器的配置有关。

机械臂由3台42步进电机驱动,实现三自由度控制。限位器则可以用来初始化机械臂位置,合理校准机械臂对应的笛卡尔空间坐标下的状态。

2.2 TB6600驱动器

        驱动步进电机往往需要驱动器帮助,常见的步进电机驱动器有:TB6600、A4988、DM542、DMA860HULN2003等。其中,大部分步进电机驱动器用法和接线思路大致相同,驱动电机的原理也基本一样。

        项目中使用的步进电机驱动器为TB6600TB6600是一款专业的两相步进电机驱动器,兼容STM32Arduino其他多种主控器,可实现电机正反转控制,旋转角度控制等功能。步进电机驱动是一种电子设备,通常作为桥梁来连接控制器、电源和步进电机。虽然控制器的处理性能很强大,但是它本身的输出能力(电流)却很弱小。它需要一个中间桥梁去连接电机和主控,并同时为电机提供足够的电源。

        TB6600步进电机驱动器采用H桥双极恒相流驱动,可直接用9~42VDC供电,可选择7档细分控制1、2/A、2/B、4、8、16、32),8档电流控制0.5A、1A、1.5A、2A、2.5A、2.8A、3.0A、3.5A)。最高支持4A电流输出。信号端都有配有高速光电隔离,防止信号干扰,并且支持共阴共阳两种信号输入方式。出于安全考虑,驱动器支持脱机保持功能,能够让用户在通电状态下调试。内置温度保护和过流保护,可适应更严苛的工作环境。 驱动器适合驱动57、42型两相、四相混合式步进电机,能达到低振动、低噪声、高速度的驱动效果。可以适用于机械人控制,3D打印等高精度应用领域中。

       通过拨动TB6600侧边的拨码开关设置步进电机的细分电流, 当拨码开关向下拨动则为ON,上图为作者设置的步进电机为16细分,电流设置为1.0A分析:正常情况下,步进电机的步距角为1.8°,转动一圈需要200脉冲,当设置为16细分则需要16×200=3200脉冲(一个脉冲步距角为0.1125°)。而电流拨码开关的设置只要保证输出电流别超过步进电机电流的运载上限就行。

TB6600信号线的共阴和共阴接法:

(1)共阴接法:分别将PUL-,DIR-,EN-连接到控制系统的地端,脉冲输入信号通过PUL+接入,方向信号通过DIR+接入,使能信号通过EN+接入。若需限流电阻,限流电阻R的接法取值与共阳极接法相同。

(2)共阳接法:分别将PUL+,DIR+,EN+连接到控制系统的电源上,如果此电源是+5V则可直接接入,如果此电源大于+5V,则须外部另加串联限流电阻R,保证给驱动器内部光藕提供8到15mA的驱动电流。脉冲输入信号通过PUL-接入,方向信号通过DIR-接入,使能信号通过EN-接入。

特别注意:作者建议大家采用共阴接法,方便且不容易犯错。

特别注意:

初学者接触步进电机与步进电机驱动器时,很容易接错相位线导致出现缺陷漏项发现。所以,当发现信号线电源线都满足驱动要求,但无法驱动步进电机亦或是步进电机驱动异常时(出现丢步,转动噪音等)。问题往往可能出现在相位线接错了,读者朋友们可以去找步进电机厂商去拿一下步进电机的相位线说明。

三、5V步进电机与ULN2003驱动器

        5V五线四相步进电机是一种常见的小扭矩电机,本项目中采用此电机通过机械结构驱动机械臂爪子进行物体抓取。该型号电机往往使用ULN2003驱动器配合使用,UNL2003器件是高电压大电流达林顿晶体管阵列。

        该直流减速电机直径:28mm 电压:5V 步距角度:5.625×1/64 减速比:1/64;步距角:5.625 / 64 = 0.087度 (也就是说理论上,你给一个脉冲,电机外部轴转动0.087度)也就是说一个脉冲内部转子转5.625度,但是由于减速64倍,所以外部轴只转了0.087度那么外部轴要转一圈的话,需要360/0.087=4096个脉冲。采用4相8拍驱动的话,8个脉冲是一个周期,那么就需要4096/8=512个周期,外部轴刚好转一圈。

电机的驱动一般分为3种方法

一.  1相励磁法:每一瞬间只有一个线圈相通,其它休息。

优点:简单,耗电低,精确性良好。(缺点)力矩小,振动大,每次励磁信号走的角度都是标称角度。1相励磁法:A->B->C->D

二、 2相励磁法:每一瞬间有两个线圈导通。

优点:力矩大,震动小。缺点:每励磁信号走的角度都是标称角度。2相励磁法  AB->BC->CD->DA

三、 1-2相励磁法:1相和2相交替导通。

优点:精度较高,运转平滑,每送一个励磁信号转动1/2标称角度,称为半步驱动。(前两种称为4相4拍,这一种称为4相8拍)1-2相励磁法  A-->AB-->B->BC->C-->CD->D-->DA

        ULN2003驱动板上的IN1、IN2、IN3、IN4四个引脚和单片机的IO口直接使用杜邦线连接,为了方便初次学习ULN2003驱动板的朋友理解,这里仅具体给大家讲解1相励磁法,如下图所示:

        上图4个定子线圈分别为A、B、C、D,我们依次给A、B、C、D通电,则可实现电机的转动,这个就是上面提到的1相励磁法。使用ULN2003驱动板时,我们只需要将IN1、IN2、IN3、IN4四个引脚分别去逐个给予高电平即可(使用定时器)。

四、机械臂控制

4.1 JDY-31蓝牙控制

        JDY-31蓝牙模块基于蓝牙3.0 SPP设计,这样可以支持 Windows、Linux、android数据透传,工作频段 2.4GHZ,调制方式GFSK,最大发射功率8db,最大发射距离30米,支持用户通过AT命令修改设备名、波特率等指令,方便快捷使用灵活。

        其通常使用时接入串口引脚(UART)即可,成功与蓝牙模块建立通信后会发送CONNECTED。简单的说,JDY-31蓝牙模块本质上就是一个蓝牙转串口的设备,使用的时候直接当串口通讯进行使用即可。

        而上位机作者则选用现成开源的蓝牙调试器APP,直接创建一个针对本项目机器人的控制上位机工程。利用该APP极大的缩短了上位机开发的时间与工作量,也可以快速检验出机器人的运动控制是否满足要求(需要蓝牙调试APP的可以私信作者提供)。

JDY-31蓝牙模块的AT指令集:

序号

目的

指令

参数

响应

备注

1

查询版本号

AT+VERSION

NONE

+VERSION=…

2

复位

AT+RESET

NONE

+OK

3

断开连接

AT+DISC

NONE

+OK

蓝牙连接后有效

4

BLE蓝牙MAC地址

AT+LADDR

NONE

+LADDR=…

5

波特率设置/查询

AT+BAUD[参数]

4-9600;5-19200;6-38400;7-57600;8-115200;9-128000

+OK

128000也不丢包

6

SPP蓝牙密码配对/查询

AT+PIN[参数]

4位密码

+OK

默认1234

7

广播名设置/查询

AT+NAME[参数]

18字节以下

OK

8

恢复出厂设置

AT+DEFAULT

NONE

OK

默认JDY-31-SPP

9

串口输出状态使能查询

AT+ENLOG

1:打开 0:关闭

OK

默认为1

特别注意:购买的JDY-31蓝牙模块可能初试化的波特率不一样,读者朋友一定要去询问到厂家的初试波特率或自己使用AT指令去设置一下,否则对后续的蓝牙控制会造成很大影响。

4.2 机械臂运动学建模

        合格的机械臂产品往往都需要根据其设计的机械结构去解算其运动模型,即仅输入需要的笛卡尔空间坐标系下的位置点\left ( x,y,z \right ),即可解算出各台电机需要运转的情况。考虑到博客篇幅有限,这里仅给大家提供该机械臂的几何模型算法,后续基于树莓派与STM32的视觉抓取机械臂给大家详细介绍一下。

五、 CubeMX配置

1、RCC配置外部高速晶振(精度更高)——HSE;

2、SYS配置:Debug设置成Serial Wire否则可能导致芯片自锁);

3、TIM2配置:利用TM2定时器配置us级脉冲

4、UART3配置: JDY-31模块与STM32的蓝牙串口通讯(开启串口中断);

5、GPIO配置:PA5、PA6、PA7为机械臂方向控制引脚;PD9、PD10、PD11、PD12为5V步进电机的四相输入;PF13、PF14、PF15为机械臂电机驱动脉冲输入引脚;

6、时钟树配置:

7、工程配置:

六、代码与解析

6.1 机械臂电机控制代码

        机械臂的驱动器件为3台42步进电机,通过TB6600驱动器进行驱动。单片机MCU主要控制的是TB6600上的DIRPUL端口,其控制过程也很简单——GPIO控制即可(作者选择共阴接法,DIR-与PUL-都需接地,只需要控制DIR+与PUL+即可)。

        其中,DIR+端口的控制为GPIO的高低电平控制,该DIR+端口的高低电平输入决定了步进电机的转动方向PUL+端口则需要输入脉冲信号进行控制,脉冲频率的高低决定了步进电机的转速。当然,这里的PUL+端口的脉冲输入有2种主流方式:(1)us级延迟函数GPIO电平翻转(2)设置定时器翻转GPIO(这里作者使用us级延迟函数翻转实现脉冲)。

Motordrive.h代码:

#ifndef __MOTORDRIVER_H
#define __MOTORDRIVER_H

#include "main.h"

//电机方向控制引脚
//正转
#define MOTOR1Forward HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
#define MOTOR2Forward HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET);
#define MOTOR3Forward HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET);
//反转
#define MOTOR1Backward HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET)
#define MOTOR2Backward HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET)
#define MOTOR3Backward HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET) 

//步进电机控制
void Motor1(short dir,int speed);//步进电机1号机
void Motor2(short dir,int speed);//步进电机2号机
void Motor3(short dir,int speed);//步进电机3号机

#endif

Motordrive.c代码:

#include "Motordrive.h"
#include "tim.h"

//1号步进电机,1正转,其他反转
void Motor1(short dir,int speed)
{
	if(dir == 1)
	{
		MOTOR1Forward;		
	}
	else
	{
		MOTOR1Backward;
	}
	
	//电机脉冲控制
	HAL_GPIO_WritePin(GPIOF,GPIO_PIN_13,GPIO_PIN_SET);
	Tims_delay_us(speed);
	HAL_GPIO_WritePin(GPIOF,GPIO_PIN_13,GPIO_PIN_RESET);
	Tims_delay_us(speed);	
}

//2号步进电机,1正转,其他反转
void Motor2(short dir,int speed)
{
	if(dir == 1)
	{
		MOTOR2Forward;		
	}
	else
	{
		MOTOR2Backward;		
	}
	
	//电机脉冲控制
	HAL_GPIO_WritePin(GPIOF,GPIO_PIN_14,GPIO_PIN_SET);
	Tims_delay_us(speed);
	HAL_GPIO_WritePin(GPIOF,GPIO_PIN_14,GPIO_PIN_RESET);
	Tims_delay_us(speed);		
}

//3号步进电机,1正转,其他反转
void Motor3(short dir,int speed)
{
	if(dir == 1)
	{
		MOTOR3Forward;		
	}
	else
	{
		MOTOR3Backward;		
	}
	
	//电机脉冲控制
	HAL_GPIO_WritePin(GPIOF,GPIO_PIN_15,GPIO_PIN_SET);
	Tims_delay_us(speed);
	HAL_GPIO_WritePin(GPIOF,GPIO_PIN_15,GPIO_PIN_RESET);
	Tims_delay_us(speed);		
}

us级延迟函数:

void Tims_delay_us(uint16_t nus)
{
	__HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
	__HAL_TIM_ENABLE(DLY_TIM_Handle);
	while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
	{
	}
	__HAL_TIM_DISABLE(DLY_TIM_Handle);
}

6.2 机械爪控制代码

        机械爪部分使用5V步进电机与ULN2003驱动板驱动,将ULN2003驱动器上的IN1、IN2、IN3、IN4四个引脚循环拉高电平,即可实现对5V步进电机的控制(IN引脚循环周期的快慢决定电机转动的快慢,循环引脚顺序决定了电机转动方向)。

注意:ULN2003驱动器驱动5V步进电机的时候,电机速度是有一定限制的。技巧:可以通过ULN2003上面4个LED灯的闪烁速度来判别驱动电机转速的快慢。

crawl.h代码:

#ifndef __CRAWL_H
#define __CRAWL_H

#include "main.h"

//引脚定义
#define IN1_HIGH HAL_GPIO_WritePin(GPIOD,GPIO_PIN_9,GPIO_PIN_SET)
#define IN2_HIGH HAL_GPIO_WritePin(GPIOD,GPIO_PIN_10,GPIO_PIN_SET)
#define IN3_HIGH HAL_GPIO_WritePin(GPIOD,GPIO_PIN_11,GPIO_PIN_SET)
#define IN4_HIGH HAL_GPIO_WritePin(GPIOD,GPIO_PIN_12,GPIO_PIN_SET)

#define IN1_LOW HAL_GPIO_WritePin(GPIOD,GPIO_PIN_9,GPIO_PIN_RESET)
#define IN2_LOW HAL_GPIO_WritePin(GPIOD,GPIO_PIN_10,GPIO_PIN_RESET)
#define IN3_LOW HAL_GPIO_WritePin(GPIOD,GPIO_PIN_11,GPIO_PIN_RESET)
#define IN4_LOW HAL_GPIO_WritePin(GPIOD,GPIO_PIN_12,GPIO_PIN_RESET)

//5v步进电机控制
void stepper(short dir,int speed);

#endif

crawl.c代码:

#include "crawl.h"

//1是正转,其余是反转
void stepper(short dir,int speed)
{
	if(dir == 1)
	{
		IN1_HIGH;
		HAL_Delay(speed);
		IN1_LOW;
		IN2_HIGH;
		HAL_Delay(speed);
		IN2_LOW;
		IN3_HIGH;
		HAL_Delay(speed);
		IN3_LOW;
		IN4_HIGH;
		HAL_Delay(speed);
		IN4_LOW;
	}
	else
	{
		IN1_HIGH;
		HAL_Delay(speed);
		IN1_LOW;
		IN4_HIGH;
		HAL_Delay(speed);
		IN4_LOW;
		IN3_HIGH;
		HAL_Delay(speed);
		IN3_LOW;
		IN2_HIGH;
		HAL_Delay(speed);
		IN2_LOW;
	}
}

6.3 JDY-31蓝牙控制机械臂代码

        项目机械臂采用手机蓝牙APP进行控制,且控制所用的蓝牙APP为开源的蓝牙调试助手,具体界面如图所示。设置6个控制组件为byte类型,按下时分别对应数字1-9,松开时为数字0

bluetooth.h代码:

#ifndef __BULETOOTH_H
#define __BULETOOTH_H

#include "stm32f1xx_hal.h" 

extern UART_HandleTypeDef huart3;

#define USART3_REC_LEN  500

extern uint8_t  USART3_RX_BUF[USART3_REC_LEN];
extern uint16_t USART3_RX_STA;
extern uint8_t USART3_NewData;

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);

#endif

bluetooth.c代码:

#include "bluetooth.h"

uint8_t USART3_RX_BUF[USART3_REC_LEN];
uint16_t USART3_RX_STA=0;
uint8_t USART3_NewData;

extern int flag;		//全局变量

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)
{
    if(huart ==&huart3)
    {
                              
              USART3_RX_BUF[USART3_RX_STA&0X7FFF]=USART3_NewData; 					
              USART3_RX_STA++;  
			
              if(USART3_RX_STA>(USART3_REC_LEN-1))USART3_RX_STA=0;
			
							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x01)
							{
								flag = 1;
							}
							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x02)
							{
								flag = 2;
							}
							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x03)
							{
								flag = 3;
							}
							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x04)
							{
								flag = 4;
							}
							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x05)
							{
								flag = 5;
							}							
 							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x06)
							{
								flag = 6;
							}
							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x07)
							{
								flag = 7;
							}
							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x08)
							{
								flag = 8;
							}							
 							if(USART3_RX_BUF[USART3_RX_STA-15] == 0x09)
							{
								flag = 9;
							}							
        HAL_UART_Receive_IT(&huart3,(uint8_t *)&USART3_NewData,1);


    }
}

6.4 main函数代码

        主函数利用switch()函数与蓝牙控制代码中定义的全局变量flag进行组合使用,在while()循环函数中实现串口3中断后全局变量flag控制机械臂运动姿态。

main.c:

#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "crawl.h"
#include "Motordrive.h"
#include "oled.h"
#include "control.h"
#include "bluetooth.h"

int flag;

int main(void)
{
  //CubeMX配置的初始化代码

  HAL_UART_Receive_IT(&huart3,(uint8_t *)&USART3_RX_BUF,1);  
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    		 switch(flag)    
    		 {
    		 case(1):Motor1(0,2000);;break;
    		 case(2):Motor1(1,2000);;break;
    		 case(3):Motor2(0,2000);;break;
    		 case(4):Motor2(1,2000);;break;
    		 case(5):Motor3(0,2000);;break;
			 case(6):Motor3(1,2000);;break;
    		 case(7):stepper(0,20);;break;		//收缩
    		 case(8):stepper(1,20);;break;		//外扩
			 case(9):stop();break;				 
    		 default:break;
    		 } 	

  }
  /* USER CODE END 3 */
}

七、项目效果

基于STM32与TB6600机械臂项目

八、代码开源

3D打印件与代码地址: 基于STM32与TB6600蓝牙控制机械臂项目-嵌入式文档类资源-CSDN文库

如果积分不够的朋友,点波关注评论区留下邮箱,作者无偿提供源码和后续问题解答。求求啦关注一波吧 !!!

猜你喜欢

转载自blog.csdn.net/black_sneak/article/details/128401838