欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式
概要
本项目利用机械臂作为分拣工具,抓取物品并送到指定位置;利用光电对管作为扫描识别仪器,检测附近物品,通过返回给单片机的信号值判断是否有物品存在,再判断是否控制机械臂做出行动;利用UNO型号的Arduino芯片,作为该系统的总指挥者,Arduino控制输出PWM方波脉宽的时长,当外部输入给舵机电信号时,舵机内部具有基准电路,若与外部电压值形成电压差,进而发出信号控制舵机的旋转角度,完成抓取任务。通过三者等其他部件的设计配合,机械臂与人工智能的结合,实现抓取分拣一体化设计,做到省时省力的分拣功能,解决了当前中小快递收发站的分拣问题。
传统的物流快递入库方式是:快递工作人员扫描各个快递的二维码,扫描之后依次进入库房。这种人工工作方式效率低,且在扫码过程中容易出现漏扫的快递。结果表明,基于Arduino的物流分拣控制系统设计可以做到智能一体化,分拣物品在技术上是可行可靠的,整套系统能够表现出极好的运行性能和效率性能。
关键词:Arduino; 机械臂; 物流分拣
一、控制系统设计
1.1系统方案
物流分拣系统要求在短时间内准确快速地识别货物并检测到货物的具体位置[5],然后将货物分拣到相应的位置。运用红外光的反射原理,在一定范围内检测货物,确定货物的具体位置。为提高目前中小快递收发点人工分拣快递速率,降低快递分拣环节的成本,设计一种基于Arduino的物流分拣控制系统设计。该分拣机器人通过红外检测系统检测货物,机械臂夹取货物并放到指定位置,完成分拣工作。
综上所述,系统应实现的功能如下:
(1)通过红外光电传感器实现对快件货物位置的检测;
(2)通过程序及Arduino实现数字识别[6];
(3)操作机械臂实现对货物分拣。
1.2 系统工作原理
(1)快件货物原理:红外光电传感器在检测到物品时返回电压值和未检测到物品返回的电压值不同(当传感器检测到物品时返回模拟量电压值0V,即数字量‘0’;当传感器未检测到物品时返回模拟量电压值5V,即数字量‘1’)根据返回的数据确定是否存在物品;
(2)串口通讯原理:在串口通讯中,Arduino串口接收的是电压信号,RX接受信号,TX发送数据,将Arduino与电脑通过数据线相连,当二者只有具有相同的波特率时,才可以进行数据传输。Arduino串口每次只读取一个字节,每个字节有八位;
(3)舵机控制原理:舵机内部一般有三条引线,红色的接正极,灰色的线接负极,有的舵机负极连接黑色线,橙色的这条线接PWM信号正极,PWM负极接电源负极。舵机一般使用5V到6V电压就可以,通过控制占空无法来控制舵机的角度,真正控制舵机角度的是脉宽的绝对时长。一般舵机是用0.5-2.5毫秒的脉宽时长来控制舵机角度,舵机的输出轴角度只跟脉宽时长的绝对值有关,与其他变量无关。当实际角度与应该保持的角度不一致时,舵机电路驱动电机正转或反转,通过齿轮组把舵机的输出轴调节到应该保持的位置。该设计的舵机转动角度为0-180度,舵机输出保持0度或小于0度,当脉宽时长等于0.5毫秒时,舵机的输出角度为0度;当脉宽时长为1毫秒时,舵机的输出角度为45度;脉宽时长每0.5毫秒的增加,旋转角度就随之增加45度,以此来得到相应的舵机角度。
1.3方案设计
1.3.1快递检测电路方案设计
快递检测电路要求实现对快递准确检测的功能。
方案一:使用TSL1401线性CCD传感器,它是一种特殊半导体器件,CCD在摄像机里是一个极其重要的部件,它起到将光线转换成电信号的作用,类似于人的眼睛。TSL1401线性CCD传感器包含 128个线性排列的光电二极管。
方案二:使用红外光电传感器,红外光电传感器模块有一对感光触头,一个负责发送红外光,发射出去的红外光有物体反射回来后会被接收端接收。传感器内部检测电路根据光束的强弱判断物体的存在。通过使用一排光电传感器组成一个模拟的、离散的线性CCD传感器来检测物品位置。
方案一使用CCD传感器虽然检测精度高,但由于Arduino主控模块运算速率有限且CCD传感器价格较贵;方案二使用红外光电传感器虽然检测距离有限,但通过使用多个传感器同时使用,也可以实现对快递的检测功能,而且此方案成本可观,Arduino主控模块运算速率足够使用。因此,选择方案二。
1.3.2控制电路方案设计
控制电路要求控制机械臂完成对快递的抓取和搬运功能。
方案一:机械臂上各个舵机串级控制。数字舵机可以ID识别,总线通讯。每个舵机都可以设置ID号,用于舵机的识别。舵机ID默认为1,可以自行修改。控制器与舵机之间采用单总线方式通信,通信波特率为11500。用户可以对每个舵机分配一个ID号,控制器发出的指令中包含ID信息。只有匹配上ID号的舵机才能完整地接收这个指令,并按照指令执行动作;
方案二:机械臂上各个舵机分别控制。每个舵机分别控制,互不影响。
方案一机械臂上各个舵机串级控制,虽然控制精度高,硬件接线简单,节约主控板I/O口,但是串级控制编程困难、调试难度大需花费大量时间;而方案二机械臂上各个舵机分别控制,虽然需要更多I/O口,但控制起来更加方便。综上,选择方案二机械臂上各个舵机分别控制。
控制电路的基本组成如图1.2所示。Arduino主控模块[7]将控制指令发送到各个舵机进而控制机械臂,做出相应动作,实现对快件的夹取。
图1.2 控制电路的基本组成图
二、硬件电路设计
2.1主控模块的选择
2.1.1 单片机及其选型介绍
单片机问世之后,已广泛应用在生活中中各个领域,单片机具有体积小、成本低、易产品化等特点,受到广大用户的青睐。现在市场上有很多种类的单片机,用户需要根据自己项目的特点,选择最适合自己项目的单片机。在资金等条件允许的情况下,尽量选择功能丰富,扩展能力强的单片机。
综上,适合本系统的单片机有51系列单片机和Arduino单片机。但Arduino与51系列单片机相比有以下优点:
(1)Arduino是单片机二次开发的产物。做项目时,普通单片机只是散件,单片机的软件设计和硬件设计都需要自己做。但是Arduino是半成品,里面有已经完成好的各种库函数模块等其他软硬件设计,只要把相应的模块组合在一起,再复制代码就可以工作了。这样对初学者来说,尽管不太了解代码,也可以直接使用Arduino,完成编程等操作。Arduino的好处就在于开发简单,使用方便;
(2)Arduino在软件编程时,编程页面有一个直接可以让编程者看到的Arduino IDE窗口监视器。可以直接观察数据,非常直观。在Setup里初始串口,然后在想要的位置直接用Serial.println打印,可以监视打印的各种数据;
(3)Arduino核心板大部分使用的是AVR单片机作为核心,这就是他们之间的联系。Arduino较单片机的运算速度更快、更稳定、编程更简单;
(4)使用Arduino做项目,几乎不用考虑硬件部分的设计,可以按需求选用Arduino的控制板、扩展板等组成自己的需要的硬件系统;
(5)Arduino内部有专门的PWM方波输出口,在硬件方面可以简便控制电机或舵机等部件,方便大家使用;
(6)Arduino单片机系统开发的功能多种多样,型号繁多,可以根据不同需要,选择最适合的型号,可以满足大部人的需要[9]。
综上,选择使用Arduino单片机作为系统的主控芯片。Arduino主控芯片图如图2.1所示。
图2.1 Arduino主控芯片图
三、软件设计
3.1系统主程序设计
如图3.1所示。程序开始后先初始化检测标志位,防止随机变量对程序的影响,再初始化机械臂位置,让机械臂复位[19]。系统开始正常工作,当红外光电传感器检测到有快递运来并确定快递位置时,主控板给舵机发出控制信号,控住舵机将快递夹取到相应位置。
图3.1 主程序流程图
原理图
源程序清单
附录2 源程序清单
#include <Servo.h>
#include <WMSBoard.h>
Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
int i=0;
int myservo1=60;
int myservo2=0;
int myservo3=140;
int myservo4=20;
int flag=0;
void setup()
{
Serial.begin(9600);
servo1.attach(3);
servo2.attach(5);
servo3.attach(6);
servo4.attach(9);
pinMode(2, INPUT);
pinMode(4, INPUT);
pinMode(7, INPUT);
pinMode(8, INPUT);
pinMode(10, INPUT);
pinMode(12, INPUT);
pinMode(11, INPUT);
}
void loop()
{
while(1)
{
jiance();
switch (flag)
{
case 1:dongzuoyi(); break ;
case 2:dongzuoer(); break ;
case 3:dongzuosan(); break ;
case 4:dongzuosi(); break ;
case 5:dongzuowu(); break ;
case 6:dongzuoliu(); break ;
case 7:dongzuoqi(); break ;
default :fuwei(); break ;
}
flag=0;
}
}
void jiance()
{
int LED1 =digitalRead(2);
int LED2 =digitalRead(4);
int LED3 =digitalRead(7);
int LED4 =digitalRead(8);
int LED5 =digitalRead(10);
int LED6 =digitalRead(11);
int LED7 =digitalRead(12);
Serial.println(LED1);
Serial.println(LED2);
Serial.println(LED3);
Serial.println(LED4);
Serial.println(LED5);
Serial.println(LED6);
Serial.println(LED7);
if(LED1==0)
{
delay(2000);
if(LED1==0)
{
flag=1;
}
}
if(LED2==0)
{
delay(2000);
if(LED2==0)
{
flag=2;
}
}
if(LED3==0)
{
delay(2000);
if(LED3==0)
{
flag=3;
}
}
if(LED4==0)
{
delay(2000);
if(LED4==0)
{
flag=4;
}
}
if(LED5==0)
{
delay(2000);
if(LED5==0)
{
flag=5;
}
}
if(LED6==0)
{
delay(2000);
if(LED6==0)
{
flag=6;
}
}
if(LED7==0)
{
delay(2000);
if(LED7==0)
{
flag=7;
}
}
}
void fuwei()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
}
void dongzuoyi()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 65 );
delay(800);
servo1.write(180 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 65 );
delay(800);
servo1.write(50 );
servo2.write( 95 );
servo3.write( 150);
servo4.write( 65 );
delay(800);
servo1.write(50 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 65 );
delay(800);
servo1.write(50 );
servo2.write( 50 );
servo3.write( 180 );
servo4.write( 0 );
delay(800);
servo1.write(50);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 0 );
delay(800);
servo1.write(180);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 0 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 0 );
delay(1000);
}
void dongzuoer()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 70 );
delay(800);
servo1.write(180 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 70 );
delay(800);
servo1.write(50 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 70 );
delay(800);
servo1.write(50 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 70 );
delay(800);
servo1.write(50 );
servo2.write( 50 );
servo3.write( 180 );
servo4.write( 10 );
delay(800);
servo1.write(50);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 10 );
delay(800);
servo1.write(180);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 10 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 10 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 180 );
servo4.write( 10 );
delay(1000);
}
void dongzuosan()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 81 );
delay(800);
servo1.write(180 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 81 );
delay(800);
servo1.write(50 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 81 );
delay(800);
servo1.write(50 );
servo2.write( 60 );
servo3.write( 180 );
servo4.write( 81 );
delay(800);
servo1.write(50 );
servo2.write( 50 );
servo3.write( 180 );
servo4.write( 20 );
delay(800);
servo1.write(50);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 20 );
delay(800);
servo1.write(180);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 20 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 20 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 20 );
delay(1000);
}
void dongzuosi()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 83 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 83 );
delay(800);
servo1.write(50 );
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 83 );
delay(800);
servo1.write(50 );
servo2.write( 60 );
servo3.write( 180 );
servo4.write( 83);
delay(800);
servo1.write(50 );
servo2.write( 50 );
servo3.write( 180 );
servo4.write( 130 );
delay(800);
servo1.write(50);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 130 );
delay(800);
servo1.write(180);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 130 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 130 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 130 );
delay(1000);
}
void dongzuowu()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 89 );
delay(800);
servo1.write(180 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 89 );
delay(800);
servo1.write(50 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 89 );
delay(800);
servo1.write(50 );
servo2.write( 60 );
servo3.write( 180 );
servo4.write( 89 );
delay(800);
servo1.write(50 );
servo2.write( 50 );
servo3.write( 180 );
servo4.write( 145 );
delay(800);
servo1.write(50);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 145 );
delay(800);
servo1.write(180);
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 145 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 140 );
servo4.write( 145 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 145 );
delay(1000);
}
void dongzuoliu()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 99 );
delay(800);
servo1.write(180 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 99 );
delay(800);
servo1.write(50 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 99 );
delay(800);
servo1.write(50 );
servo2.write( 60 );
servo3.write( 180 );
servo4.write( 99 );
delay(800);
servo1.write(50 );
servo2.write( 50 );
servo3.write( 180 );
servo4.write( 160 );
delay(800);
servo1.write(50);
servo2.write( 100 );
servo3.write( 150 );
servo4.write( 160 );
delay(800);
servo1.write(180);
servo2.write( 100 );
servo3.write( 150 );
servo4.write( 160 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 150 );
servo4.write( 160 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 160 );
delay(1000);
}
void dongzuoqi()
{
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 90 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 108 );
delay(800);
servo1.write(180 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 108 );
delay(800);
servo1.write(50 );
servo2.write( 95 );
servo3.write( 150 );
servo4.write( 108 );
delay(800);
servo1.write(50 );
servo2.write( 60 );
servo3.write( 180 );
servo4.write( 108 );
delay(800);
servo1.write(50 );
servo2.write( 50 );
servo3.write( 180 );
servo4.write( 180 );
delay(800);
servo1.write(50);
servo2.write( 100 );
servo3.write( 150 );
servo4.write( 180 );
delay(800);
servo1.write(180);
servo2.write( 100 );
servo3.write( 150 );
servo4.write( 180 );
delay(800);
servo1.write(180 );
servo2.write( 100 );
servo3.write( 150 );
servo4.write( 180 );
delay(800);
servo1.write(180 );
servo2.write( 90 );
servo3.write( 180 );
servo4.write( 180 );
delay(1000);
}
四、结论
本设计通过分析目前中小快递收发点人工分拣快递速率慢,效率低下且考虑到分拣环节的成本问题,提出使用机械臂系统进行分拣的方案,提高快递收发点分拣快递速率,降低了快递分拣环节的成本,进行了具体的方案设计,并且进行了方案验证。通过完成系统功能设计、硬件部分设计、软件部分设计、程序的编写、调试系统的工作,得出了该系统设计能够满足各项功能需求的结论。
该设计实现的功能有:
(1)通过红外光电传感器实现对快件货物位置的检测;
(2)通过程序及Arduino[17]实现数字识别;
(3)操作机械臂实现对货物分拣。
五、 文章目录
目 录
摘 要 I
Abstract II
引 言 1
1 控制系统设计 4
1.1 系统方案 4
1.2 系统工作原理 4
1.3 方案设计 5
1.3.1快递检测电路方案设计 5
1.3.2控制电路方案设计 5
2 硬件电路设计 7
2.1主控模块的选择 7
2.1.1 单片机及其选型介绍 7
2.1.2 复位电路的介绍 8
2.1.3 稳压电路的介绍 9
2.2 红外光电传感器模块 9
2.3 舵机模块 10
2.4 机械臂拼装 11
3 软件设计 14
3.1 系统主程序设计 14
3.2 快递检测子程序设计 14
3.3 夹取快递子程序设计 15
4 仿真与调试 16
结 论 17
参考文献 18
附录1 原理图 20
附录2 源程序清单 21
致 谢 32