目 录
摘 要
Abstract
引 言
1 总体方案设计
1.1 系统方案设计
1.2 系统工作原理
2 硬件电路的设计
2.1 主控模块设计
2.2 驱动模块设计
2.3 时钟模块设计
2.4 总电路设计
3 软件设计
3.1 Arduino开发环境
3.2 主程序设计
3.3 抬笔落笔的子程序设计
3.4 摆臂子程序设计
4系统调试
4.1 系统硬件调试
4.2 系统软件测试
结 论
参考文献
附录1 舵机及DS3231参数
附录2 源程序清单
致 谢
摘 要
为了提高人类生产生活的工作效率,减轻人工抄写的工作强度,顺应科学技术的飞速发展,利用开发板为主控制器,通过下达指令控制位于3D打印写字板下方的舵机来控制笔距离纸面的高低位置,以达到模仿人类抬笔落笔的目的。同时控制位于3D打印机械臂连接处的左右舵机,带动左右小臂进行运动,控制笔尖在板上的位置,配合着底部舵机的运动实现对数字等字体的书写。
结果表明,基于Arduino板的写字机能够代替人工手写,与此同时,整套装置也表现出极好的灵活性、智能化。同时也说明,智能机器人对于帮助人类完成书写工作以及提高人类的书写效率起到了至关重要的作用,机器人书写技术可以使机器人在通过对字体的学习后进行自主书写。而由于机器人写字技术具有灵活性、智能化、高可靠性、高精度的特点,因此,人们致力于将此项技术应用于生活实际工作中,以提高工作效率,并不断拓展写字机的功能。目前,写字机的应用领域已经大大拓宽,这意味着该课题的可行性。
关键词:机械臂; 舵机; 灵活性; 智能化
Abstract
In order to improve the efficiency of human production and life, reduce the intensity of manual transcription, and comply with the rapid development of science and technology, Arduino board is used as the main control chip to control the servo located below the 3D printing board by issuing instructions to control the height of the pen tip from the paper surface, so as to achieve the purpose of imitating human lifting and writing. At the same time, control the servo located at the connection of 3D printing forearm, drive the left and right forearms to move, control the position of the pen tip on the board, and write the number and other fonts according to the movement of the steering gear at the bottom.
The results show that the writing machine based on Arduino board can replace manual handwriting, and has a speed and stability exceeding that of human handwriting. At the same time, the whole device also shows excellent flexibility and intelligence. At the same time, it also shows that intelligent robots play a crucial role in helping humans complete writing and improving their writing efficiency. Robot writing technology can enable robots to write independently after learning fonts or after receiving instructions from clock modules.Thanks to the flexibility and intelligence of the writing machine, people will be able to apply this technology to their lives and constantly exploit its functions. At present, the application field of writing machine has been greatly expanded, which means the feasibility of the subject.
Keywords: mechanical arm; servo; flexibility; intelligent
引 言
由于Arduino入门简单,对电路知识的要求并不高,并且发展前景好,所以人们越来越重视此领域的开拓,同时,由于5G时代的到来,VR、AR等可穿戴设备的应用将会更加普及,这就为Arduino提供了更多的发展机会,而且随着科技的进步,人们创新意识显著增强,Arduino这种易上手、稳定性高的的技术将会更受人们的青睐。本项目主要研究写字机实现书写数字并记录时间的问题,比较深入地研究了Arduino板、动力学、轨迹规划、舵机驱动等问题。
文字是人类文明延续的重要媒介,知识经济时代已经到来,生产化的高科技产品已经逐渐融入到人类的生活中。机器人技术是一种新的科技领域,生产与生活中不可或缺的一部分。并且为国家的制造业打下了新的基础。不仅如此,这项技术正在逐渐的改变我们的生活,原本繁杂的工作变得越来越简单易处理,原本靠人类自身无法实现的工作也逐渐变成了可能,可以说是开创了一个新时代。
目前为止,人类记录时间的、记录数据的方式还停留在手动阶段,虽然很多电子设备中都内置了精密的时钟,但并不能人性化的将时间或重要的数据自动记录下来,而智能写字机的出现将代替人类完成这些繁杂的工作。智能写字机综合了计算机、控制论、仿生学等多学科知识的技术产品,其应用场景广泛,不仅是AI技术的新思维,更是对提高人类书写工作效率有着重大意义。不仅如此,写字机的功能极具开发价值,不仅可以成为记录时间的工具,也可以加入激光头进行激光雕刻,甚至还可以绘制一些复杂的绘画作品。可以说写字机不光是一台会写字的机器,还是一个多功能的艺术创作机器人。
在写字机进行绘画的实验中,王晓丽、宫晓博等改善了笔架的运行轨迹,使绘画作品更加生动;此外,在写字机汉字书写实验中,南京林业大学机器人研究所也取得不错的成果,成功的对笔的运行轨迹进行了重新编程,拓展了更多书写字体。
与此同时,写字机在国外也有了多项研究成果。MF Crainic等人提出了一种促进证书或传统信用证创建的方法,实现了写字机的机械臂可以在斜面上进行书写。K Tahara等人还提出了一种新的控制方案,该方案实现了使笔尖可以从初始位置运动到平面指定任意位置。
当前,写字机器人存在如下三个方面的问题:①写字机器人不够智能,太过于依赖已有的程序,如果程序发生错误,就会影响整个写字过程。系统缺乏异常容错能力,且系统自身并不能找到错误原因。②当前的写字机器人只是在同一水平面简单的程序化的进行书写,不能实施多角度的操作,只局限一个方向。③当前的写字机器人只局限于纸质品上绘画,写字操作不够精细,且需要人工辅助。最重要的是写错之后不能自动修改。
本项目围绕如下几个方面进行研究:①关于机械控制,结合机械结构、前进和后退运动学、工作空间、力学和轨迹规控制写字机。②对在空间平面、柱面及球面的多角度绘制。③模块化设计,针对不同材料、笔触模块的相应设计。④标绘时钟,为了能够有效地记录时间数字,需要对时钟模块进行学习。仿生人写字绘画的动作,使得绘制的作品更具人性。
本文的主要工作如下:
第一章重点说明了系统的方案设计,主要阐述了系统的功能和设计目标,并根据设计目的选择合适的驱动模块,做出了系统的总体方案设计框图。
第二章介绍了写字机的硬件设计,其中包含各个模块的设计原理,并根据系统的设计要求选取Arduino板的型号,选择最适合要求的舵机和时钟模块。本章重点介绍了舵机模块的电路设计,以及舵机与Arduino板之间的协作。
第三章讲述了系统的软件设计;简要介绍了系统的开发环境以及重要函数和系统流程图。
第四章是写字机的调试部分,囊括了系统的硬件测试以及软件测试,并就本设计出现的问题,做了简单的论述以及解决办法。
1 总体方案设计
1.1系统方案设计
写字机系统是由一个主控制器、一个执行环节来完成对笔的控制,使笔能够在写字板上写出简单的字体,通过对资料的采集,本系统的可供选择的有步进电机控制执行和舵机控制执行,具体方案如下:
方案一:写字机的整体系统由计算机、Arduino板、步进电机以及舵机组成,其中Arduino板为主控制器,步进电机和舵机则控制笔移动。文本信息由计算机转换成G代码传送给Arduino板,其内部程序会将G代码转换成相应的程序代码来控制步进电机和舵机的运动。写字机的主要动力驱动是由步进电机完成的,实践中控制每输出一个控制脉冲,电机就运转带动笔架,进而实现仿写字体。此方案可以仿写人类字体,精度高,但价格高,结构复杂,难实现。
方案二:写字机的整体系统由计算机、Arduino板、时钟模块和舵机四部分组成,其中Arduino板主要作为主控制器,三个舵机主要控制笔的抬落以及书写工作。主要由上位机将信号传送到下位机Arduino板中,在经过简单的几个坐标运算,计算出每个要写的数字或汉字中笔画的重要连接点,同时根据机械臂的几何原理,控制左右机械臂的舵机齿轮在0至180度之间转动,从而带动机械臂与笔的运动,进而进行写字。再利用时钟模块,可以书写出实时的时间。此方案的最大优点是拓展了智能写字机的功能,使其能够自动记录时间,并且价格便宜,结构简单,易实现,并且方便携带。其缺点是写字精度不够且只能写一些简单的汉字。
经上述比较,虽然方案一可以写出大量的切精度高的仿写字体,但是研究范围太大,且价格昂贵,而方案二价格便宜并且全舵机控制写字更容易实现,并且增加时钟模块拓展了传统写字机的功能,更具创新意义,故选择方案二通过舵机带动机械臂进行书写。
1.2 系统工作原理
智能写字机系统采用自动化控制,要求实现抬笔落笔、写字、记录时间,所以系统分为左右以及抬臂舵机部分、控制器部分、时钟模块部分,其中控制器采用Arduino板来控制写字信号的传输,时钟模块部分则采用时钟芯片传输实时时间信号,舵机部分则采用微型舵机完成对写字信号的执行,系统可以在每一分钟记录一下时间,也可以自行安排写字内容,即一个Arduino控制器,操控写字机系统中若干组成模块的正常运作,其控制系统框图如图1.1所示。
图1.1 控制系统框图
2 硬件电路的设计
2.1 主控模块设计
2.1.1 主控模块的选择
Arduino是个基于开放源代码的软硬件平台。他的硬件具有丰富的接口,有数字 I/O 口、模拟 I/O 口,同时支持 SPI、IIC、UART 串口通信。常见的主板型号有Arduino UNO、Arduino Mega 2560、Arduino101、Arduino Leonardo 等。其中适用于本设计的型号有Arduino Uno和Arduino101[2]。
方案一:Arduino101是一款拥有入门级别的主板,其拥有高性能、低功耗的特点,同时拥有神经元功能,适用于机器学习,但是其价格昂贵,有时则会出现手动复位的问题,其强大的功能反而被UNO的外形所限制。
方案二:Arduino UNO作为主控芯片时,实物如图2.1所示,其选用ATmega328 MCU控制器为基础,具备14个数字输入/ 输出引脚(其中6路可用于PWM输出)、6路模拟输入、一个 16MHz陶瓷谐振器、一个USB接口、一个电源插座、一个 ICSP接头和一个复位按钮[3]。其优点主要是性价比很高,同时提供了自动复位的设计,可以通过软件自动复位,不需要再按复位按钮,同时具有极高的稳定性,其缺点是性能中庸。
综上对比,UNO作为Arduino平台的参考标准模板,其价格便宜,更适合入门学习,并且相较于Arduino 101拥有更高的稳定性,所以选择Arduino UNO作为主控芯片,其具体实物如图2.1所示。
图2.1 Arduino UNO实物图
2.1.2 Arduino的最小系统
最小系统主要由两个部分组成,分别为:ATmega328p芯片 、晶振电路,其电路设计如图2.2所示。
图2.2 Arduino UNO最小系统
本设计中Arduino板的电压在4~5V之间可以正常工作。电源部分使用的是USB电源线,可以连接手机充电插头或者5V的移动电源给系统供电。
在晶振电路中有两个独立的反向放大器,即输入端XTAL1和输出端XTAL2,它们不仅可以与石英晶振配合,作为单片机的内部振荡器。而且能够单独作为一个元器件,需要被外部时钟驱动来使用。图2.3就是内部时钟模式。也就是说,晶振电路中的输入端和输出端分别连接两个电容和一个1MHz的石英晶振,内部振荡器便产生了。而与其连接的两个电容C4和C3会对振动频率起作用,进而起到调节频率的效果。
图2.3 晶振电路
2.2 驱动模块设计
本设计主要靠舵机驱动,其内部结构主要有小型马达、小型电路板、齿轮等,舵机的外部接线为黄、红、棕三种颜色。当舵机接收到接收机的信号后,其内部控制电路会检测此时舵机轴的角度,如果此时轴的角度与控制信号不同,则内部的小型马达就会转动到指定的角度,如果轴的角度与信号相一致,则马达不会转动。
方案一:SG90型号舵机是最基础,使用最广泛的舵机,并分为90度、180度、360度旋转角度版本,可以控制机械臂摆动并且调整笔的高度,其价格便宜,属于模拟舵机类型,适用于固定翼、直升机KT、小型机器人、机械手等模型。优点是性价比高,缺点是不够耐磨,实物如图2.4所示。
图2.4 SG90舵机实物图
方案二:MG90舵机相当于SG90舵机的金属齿轮加强版,可以控制机械臂的摆动以及调整笔架的高度,安装尺寸与SG90略微不同,其优点是采用金属舵机齿轮,更加耐磨,但是缺点是其价格也更贵,而且重量达13.6g,不够轻便,适用于450直升机斜盘舵机、小型机器人、航模遥控飞机等。
综上比较,SG90舵机更加便宜与轻便,并且能够契合本设计功能的需要,与MG90舵机想比性价比更高。所以选择SG90型号舵机作为驱动,其具体电路图如图2.5所示。
图2.5 SG90舵机电路图
2.3 时钟模块设计
时钟模块是通过Arduino板内部或者外部振荡器,处理所提供的高频脉冲,成为Arduino板内部时钟信号。作用是来配合外部晶体实现振荡的电路,提供给Arduino板一个运行时钟。
方案一:DS1302时钟的优点是功耗较低并且性能高,采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAI数据。与此同时,DS1302拥有主电源/后各电源双电源引脚,具备了电流充电的能力。但是DS1302时钟的缺点也很明显,其精度不够高,容易受到外部环境影响[4]。
方案二:DS3231时钟的优点是当电源断开时仍能计时,并且精确度高、成本低、使用寿命长。晶振不仅提高了元器件的精确度,还减少了生产线的元件数量。与此同时,DS3231还提供商用级和工业级温度范围,采用16引脚、300mi1的S0封装[5]。高精度的电压基准和比较器电路用来监视VCC状态,检测电源故障,提供复位输出,能够及时自动切换到备份电源。
除此之外,DS3231还有其他一些优点,其高稳定性保证了控制电路可以进行自动的检测,实现主电源与备用电源的切换。当主电源重新加电或电压值返回到容许范围内时,片上复位功能可用来重新启动系统微处理器。实物如图2.6所示。
图2.6 DS3231模块实物图
综上方案比较,由于DS1302模块精度不高而且不够稳定,在设计中并不容易控制,所以最终采用DS3231模块,其具体电路图如图2.7所示。
图2.7 DS3231模块电路图
2.4 总电路设计
在总电路设计之前,将左右臂舵机以及抬臂舵机固定好,再将机械臂组装好,其中,先将Arduino板与拓展版相连接,各个插口一一对应,再将三个舵机的红、黄、棕接线分别接到拓展板的对应位置,DS3231模块的VCC和GND分别对应着接到拓展板的IIC口,将左舵机的信号线接 Arduino拓展板的三口,右舵机信号线接 Arduino拓展板的四口,抬臂舵机信号线接 Arduino拓展板的五口,最后DS3231模块的SCL对应着接 Arduino拓展板的SCL口,DS3231模块的SDA对应着接 Arduino拓展板的SDA口。具体电路图如图2.8所示。
图2.8 总电路设计图
3 软件设计
3.1 Arduino开发环境
Arduino IDE是一款主要用于Arduino程序编写和开发的专业工具,支持在线烧录,用户可以免费下载修改程序。可通过USB供电,无需外接电源,也可以使用外部9VDC输入[6]。其应用强大,利用Arduino可以实现以往只能使用鼠标、键盘等输入的装置的互动内容。综上,这是一款容易入门,使用方便的编程软件,其界面十分简洁,如图3.1所示。
图3.1 Arduino IDE界面
3.2 主程序设计
程序部分主要包括笔的抬与落,舵机控制摆臂,此时笔落下。抬笔状态意味着没有书写任务;记录摆臂的轨迹,会以产生中断的方式对行程进行计数;写字部分是关键,摆臂的角度很关键。同时分析要书写的时间汉字,规划机械臂运行的轨迹,编写坐标点。
综上分析,程序主要分为:引脚的宏定义部分,擦除函数,抬笔落笔函数,空格函数,主函数等,主函数可以调用规划好的数字函数。这样可以方便的通过修改函数来修改字体,并且不用通过程序的修改。与此同时,在程序中改变调用次序,就可以改变数字或其他字的书写顺序,完成不同数字的书写。在初始化设置中,设置中断引腳(中断函数将在下面进行介绍),设置串口的波特率,打开串口,设置引脚为输出模式等[7]。循环体模块,主要是调用子函数,完成想写的单词或者是句子。主程序流程图如图3.2所示。
图3.2 主程序流程图
3.3 抬笔落笔的子程序设计
通过舵机的旋转原理可知,由于笔的抬落是由舵机控制的,舵机根据指定的参数值,旋转到指定位置。在笔抬起的过程中,根据机械臂的几何关系,90度角会起到最好的支撑作用;落笔的过程中,机械臂不再有支撑作用,所以回归零度角。由于角度是由脉冲决定的,每接收一个脉冲,舵机就会转动一个角度,这个角度是很小的,只有多个脉冲才能想要转动到需要的角度。当达到指定的角度时,便不会再转动陪。落笔的程序和起笔很是相似,只是转动的角度不一样。即用到的信号脉冲中的高电平的时间是2.0毫秒[8]。控制笔的程序流程如图3.3所示。
图3.3 控制笔的流程图
3.4 摆臂子程序设计
依据余弦定理和勾股定理可以得出两个机械臂间存在着的几何关系和舵机转动的角度关系,在写字板上建立坐标系,以右侧舵机的写字板直角为坐标原点,确定不同数字或汉字的坐标,使笔尖能够在坐标间运动,从而写出数字或汉字。因此,以左右舵机中间点为原点,向左为x轴,向前为y轴建立直角坐标系,先求坐标位置与左舵机转动角度的关系,再设笔尖在白板上的位置为(x,y),那么左右舵机的位置分别为(XO1,YO1),(XO2,YO2)。
SERVORIGHTNULI为右臂转到0度位置时舵机的角度,所以我们就可以确定右舵机转动的每一角度与笔的坐标的关系控制坐标位置的函数,左臂也是如此,把机械臂移动到目标位置的摆动角度程序设计如下:
void set _XY(double Tx, double Ty)
{
double dx, dy, c, a1, a2, Hx, Hy,;
double key_number;
delay(1);
dx = Tx - O1Y;
dy = Ty - O1Y;
c = sqrt(dx * dx + dy * dy);
a1 = atan2(dy, dx);
a2 = return angle(LI, L2, c);
key_number=(floor(((a2 + a1 - M_PI) * SERVOFAKTORLEFT) + SERVOLEFTNULL));
PWM[1] = (int)key_number;
a2 = return_angle(L2, L1, c);
Hx = Tx + L3 * cos((a1 - a2 + 0. 621) + M_PI);
Hy = Ty + L3 * sin((a1 - a2 + 0.621) + M_PI);
dx = Hx - O2X;
dy = Hy - O2Y;
c = sqrt(dx * dx + dy * dy);
a1 = atan2(dy, dx);
a2 = return angle(L1, (L2 - L3), c);
key_number = (floor(((a1 - a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));
PWM[2] = (int)key_number;
Delay20ms();
}
4系统调试
4.1系统硬件调试
在系统中,对于硬件电路的检测主要是看焊接时是否有毛刺、无光泽,电路是否有短路、开路、一些具有方向的元件是否方向弄错、电路设计错误等情况。对于漏焊、元件方向弄错的检测方法是仔细对照电路图检查实际焊接的元件是否缺少。如果发现没有或者对不上的情况下需及时的重新对照确定漏焊时及时的补焊。而对于短路、断路、虚焊这些情况,应采用数字万用表检测[9]。
经过测试,实物电路板与原理图一致,所有元器件的插接、方向均正确。
改SERVOLEFTNULL, SERVORIGHTNULL, SERVOFAKTORLEFT,SERVOFAKTORRIGHT的参数,前两个参数修改是为了使左右悬臂能够摆动至90度位置,后两个参数修改是为了能使左右悬臂能够摆动到180度位置,在调试的过程中,首先上传程序,让舵机开始带动机械臂运动,当左舵机达到180度时断开电源,调整右侧机械臂舵机为90度,同样的方式再调整右侧舵机,再调节左右臂另一个位置,要保持当一侧舵机转到180度时,另一位置都是垂直于舵机连线位置的[10]。具体角度如图4.1所示。
图4.1 摆臂角度平面图
4.2 系统软件测试
先将程序编译完成,在上传到Arduino板里,并且设置初始时间为12:30。首先要调节笔的高度,时笔尖刚好落在白板上,又不至于紧贴在白板上,影响书写,此时需要调节lift(0)函数的值,使其能够刚好触碰到白板,然后调节高抬笔的数值,使笔抬起的高度超过笔擦帽,而且要保证笔落下后刚好插进笔擦帽内,于是不断改变笔擦位置坐标( rubberx, rubbery),笔会在程序运行时先擦除掉白板上的痕迹,然后落笔写字,并且在不同的数字书写过程中会有轻微的抬笔。时间坐标修改成12:30,修改函数值结果如图4.2所示。
图4.2 修改结果图
经过多次测试后,写字机能够清晰准确写出时间数字,并且书写流畅,书写过后会自动擦除,所有软件调试功能都已通过,实现了本次设计的要求。书写时间12:30测试结果如图4.3所示。
图4.3 测试结果图
结 论
本篇论文针对减少人工书写的强度,同时代替人手动记录时间,在同时做其他工作时并不方便,造成记录偏差的问题,设计出一种基于Arduino的写字机。使用者可以根据自己的需求来记录时间数字,或是拓展其写字功能,写一些简单的汉字或图案,抑或用于设计一些文字LOGO,减少了人工书写或记录的强度。
设计是由Arduino板、舵机、DS3231模块以及外部伸展的电路组成。该系统使用的主控芯片是Arduino UNO,它使用内部的ATmega328p控制器来提高书写效率。系统用SG90舵机来控制笔架以及两个机械臂的运动,实现笔的高度以及在写字板上的位置。当接入DS3231模块时,舵机开始进入时间数字记录模式,对实时的时间开始书写,书写的速度完全可比拟人类的书写速度,并且在设计的时间点停下来。当没有插入DS3231时,还可以通过软件设计特定程序,控制写字机写出相应的汉字、英文、图案等。本设计利用ArduinoIDE软件编写C语言程序,使各个模块实现相应功能。并且Arduino板外围接口简单,功能完善,实现了基于Arduino 的写字机设计。
本设计经过了硬件以及软件的测试,各部分均达到预期功能:实现了在DS3231模块连接后对实时时间的记录功能,并且通过对程序的设计,可以实现对汉字、英文、以及图案的书写与描绘。该写字机操作简单,稳定性高,工作效率强。应用本设计产品,可以减轻人类书写工作的麻烦,并且高效记录时间,同时写拓展了智能写字机的功能。
参考文献
[1] Timothy D. Barfoot. 机器人学中的状态估计[M]. 西安: 西安交通大学出版社, 2017.4:20-25
[2] 吴竹兵. 多自由度灵巧手控制系统的设计与研究[D]. 山西: 中北大学出版社, 2017.4:123-130
[3] 刘勇, 张东升, 齐高峰. 基于Arduino的一种桌面型激光雕刻系统的研发[J]. 花炮科技与市场, 2018, 92(2):77-85
[4] 兰栋, 张国恒, 王昭武, 蓝剑锋, 苏梦梦, 王艺翔. 基于Arduino的激光雕刻机[J]. 电子世界, 2018, 38(1):35-40
[5] 田文举, 李华, 叶犇, 刘庆. 基于arduino平台的两轴激光雕刻机设计[J]. 杭州:南方农机, 2018, 49(8):81-83
[6] 伍文进, 徐中云, 严帅. 基于Arduino两轴激光雕刻机的研究与实现[J]. 机床与液压, 2018, 27(8):99-100
[7] 张宏伟. 单片机应用技术[M]. 北京: 北京理工大学出版社, 2016.6:105-110
[8] 张培仁. 机器人系统设计与算法[M]. 北京: 中国科学技术大学出版社, 2008.3:50-60
[9] MykePredko. 机器人控制器与程序设计[M]. 北京: 科学出版社, 2004.4:10-25
[10] 伍文进, 徐中云, 严帅. 基于Arduino两轴激光雕刻机的研究与实现[J]. 机床与液压, 2018, 48(8):53-60
[11] 陈玉, 谢玮, 孟宪民, 杨东岳. 智能写字机器人设计[J]. 计算机测量与控制, 2016, 23(1):45-49
[12] 石琪琦, 庄杰, 黄炜, 张佳东, 左轩尘. 基于姿态识别的机器人人机交互系统设计[J]. 计算机工程与设计, 2015, 25(7):123-125
[13] 王光建, 廖志勇, 陈雪华. 机器人写字技术及其运动参数[J]. 重庆: 重庆大学学报(自然科学版), 2003, 31(9):78-80
[14] 章杨清, 刘政凯. 利用分维向量改进神经网络在遥感模式识别中的分类精度[J].环境遥感, 1994, 81(1):140-142
[15] 章杨清, 刘政凯. MOTOMAN-UP6机器人写字功能设计与实现[J]. 机械制造与自动化, 2011, 39(1):136-140
[16] 杨振乾, 张旭东, 王子城, 高文莉, 周惠君, 周进. 基于Arduino单片机的迈克尔逊干涉仪测量改进[J]. 实验室研究与探索, 2016, 56(1):20-25
[17] 郑昊,钟志峰,郭吴. 基于Arduino的蓝牙通信系统设计[J]. 物联网技术, 2018, 52(1):30-35
[18] 程晨. Arduino开发实战指南[M]. 南京: 机械工业出版社, 2016.5: 50-75
[19] 于欣龙,郭浩赟. 硬件开源电子设计平台:爱上Arduino[M]. 北京: 人民邮电出版社, 2015.5: 60-75
[20] 唐乐. Arduino机器人制作指南[M]. 北京: 科学出版社, 2017.9: 30-105
附录1 舵机及DS3231参数
有关技术参数说明如下:
SG90舵机参数:
尺寸:21.5mmX11.8mmX22.7mm
重量:9克 (1kg=1公斤=2斤)
无负载速度:0.12秒/60度(4.8V) 0.002s/度
堵转扭矩:1.2-1.4公斤/厘米(4.8V)
使用温度:-30~+60摄氏度
死区设定:7us (7MHZ)
工作电压:4.8V-6V
位置等级:1024级
脉冲控制精度为2us
DS3231特性参数:
精度范围:0°C至+40°C范围内精度为±2ppm -40°C至+85°C范围内精度为±3.5ppm
工作温度范围商用级:0°C至+70°C 工业级:-40°C至+85°C
接口:高速(400kHz) I2C
工作电压:3.3V
数字温度传感器输出:精度为±3°C
附录2 源程序清单
//1.先调节0、180度的位置。调节到位后,再调节90度位置
//左右悬臂舵机的 0或180度位置,,数字增加,左侧舵机逆时针调整,右侧舵机顺时针调整
//【此数值可能需要调节】
#define SERVOLEFTNULL 2050 //数值减小,顺时针旋转,加大则逆时针旋转 // 2050
//【此数值可能需要调节】
#define SERVORIGHTNULL 1080 //数值减小,顺时针旋转,加大则逆时针旋转 //1050
//2.调节到位0、180,再调节下面参数
//左右悬臂舵机的90度位置,,数字增加,左侧舵机顺时针调整,右侧舵机逆时针调整
//【此数值可能需要调节】
#define SERVOFAKTORLEFT 650 //数值加大,顺时针旋转,减小则逆时针旋转//630
//【此数值可能需要调节】
#define SERVOFAKTORRIGHT 605 //数值减小,顺时针旋转,加大则逆时针旋转//605
//升举舵机的3个角度
//【此数值可能需要调节】
#define LIFT0 1800 //落笔写字 on drawing surface
#define LIFT1 2000 //写字时抬臂动作 between numbers
#define LIFT2 2200 //高抬笔架 going towards sweeper
//【此数值可能需要调节】
//
//↑↑↑↑↑↑↑↑↑↑↑↑调试成功后,将以上代码复制到主程序 ↑↑↑↑↑↑↑↑↑↑↑↑
//以上参数,请运行调试程序 plotclock ,调整好位置后,将数据复制过来
//
//笔擦的坐标位置,如不能对准笔擦可以微调单位毫米
int rubberx=72,rubbery=46; //【此数值可能需要调节】
//三只舵机的接口号
#define SERVOPINLIFT 2 //抬臂舵机
#define SERVOPINLEFT 3 //左臂舵机
#define SERVOPINRIGHT 4 //右臂舵机
// 速度 数字越小越慢,太快了容易抖 1000~2000
#define LIFTSPEED 1500
// 悬臂的长度,根据图纸测量,无需改变
#define L1 35
#define L2 57.2
#define L3 14.2
// 左右舵机轴心的位置,根据图纸测量,无需改变
#define O1X 22
#define O1Y -25
#define O2X 47
#define O2Y -25
//需要的库函数
#include <DS3231.h>
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 and 0x3f for a 16 chars and 2 line display
//时钟模块,如果没有时钟模块,请用另一个程序
DS3231 Clock;
bool h12;
bool PM;
int servoLift = LIFT2;
Servo servo1; //
Servo servo2; //
Servo servo3; //
volatile double lastX = rubberx;
volatile double lastY = rubbery;
int last_min = 0;
void setup()
{
Wire.begin();
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.setCursor(0,0);
lcd.print(“time:”);
//第一次运行 请设置时间,设置成功后请删除此行代码,或者如下格式注释掉
Clock.setMinute(9);//设置分钟
Clock.setHour(16); //设置小时
//第一次运行 请设置时间,设置成功后请删除此行代码
// 设置一个模拟时间,(小时,分钟,后面全填0)
//如果此句编译错误,请将文件包内的libraries库放到Arduino文件夹内,具体操作办法见说明文档
servo1.attach(SERVOPINLIFT); //初始化抬臂舵机 lifting servo
servo2.attach(SERVOPINLEFT); //初始化左臂舵机 left servo
servo3.attach(SERVOPINRIGHT); //初始化右臂舵机 right servo
lift(2); //高抬笔
drawTo(rubberx, rubbery); //停留在笔擦位置
delay(1000);
}
void loop()
{
int minute,hour;
minute=Clock.getMinute();
hour=Clock.getHour(h12, PM);//读取时间
lcd.setCursor(5,0);
lcd.print(hour);
lcd.print(‘:’);
lcd.print(minute);
int i = 0;
//下面代码任选一行,进行不同模式的书写
//if (last_min != minute) //每分钟书写一次时间
//if (1) //反复不间断的擦写模式
if (last_min != minute)//如需修改请复制上面代码
{
if (!servo1.attached()) servo1.attach(SERVOPINLIFT);
if (!servo2.attached()) servo2.attach(SERVOPINLEFT);
if (!servo3.attached()) servo3.attach(SERVOPINRIGHT);
lift(0);
while ((i+1)*10 <= hour)
{i++;
}number(0, 3, 111, 1);
number(0, 25, i, 0.9);
number(14, 25, (hour-i*10), 0.9);
number(25, 25, 11, 0.9);
i=0;
while ((i+1)*10 <= minute)
{i++;
}
number(32, 25, i, 0.9);
number(43, 25, (minute-i*10), 0.9);lift(2);
drawTo(rubberx, rubbery);
lift(1);
last_min = minute;servo1.detach();
servo2.detach();
servo3.detach();
}
// lift(0); //落笔写字
// number(0, 3, 111, 1); // 檫黑板
// number(0, 25, 5, 1);
// number(14, 25, 5,1);
// number(25, 25, 11,1); // 打点
// number(32, 25, 5, 1);
// number(43, 25, 5, 1);
// lift(2); //高抬笔
// drawTo(rubberx, rubbery); //【此数值可能需要调节】 默认为70 44
// lift(1);//抬笔
// servo1.detach();
// servo2.detach();
// servo3.detach();
// while(1);
}
// Writing numeral with bx by being the bottom left originpoint. Scale 1 equals a 20 mm high font.
// The structure follows this principle: move to first startpoint of the numeral, lift down, draw numeral, lift up
//这里是写字的函数,如果你觉得字写的丑,可以自行修改字体,结果可能是更丑
//还可以自行增加其他内容,比如字母甚至是汉字
void number(float bx, float by, int num, float scale) {
switch (num) {
case 0:
drawTo(bx + 12 * scale, by + 6 * scale);
lift(0);
bogenGZS(bx + 7 * scale, by + 10 * scale, 10 * scale, -0.8, 6.7, 0.5);
lift(1);
break;
case 1:
drawTo(bx + 3 * scale, by + 15 * scale); //
lift(0);
drawTo(bx + 5 * scale, by + 20 * scale);// drawTo(bx + 10 * scale, by + 20 * scale);
drawTo(bx + 5 * scale, by + 0 * scale);
lift(1);
break;
case 2:
drawTo(bx + 2 * scale, by + 12 * scale);
lift(0);
bogenUZS(bx + 8 * scale, by + 14 * scale, 6 * scale, 3, -0.8, 1);
drawTo(bx + 1 * scale, by + 0 * scale);
drawTo(bx + 12 * scale, by + 2 * scale);// drawTo(bx + 12 * scale, by + 0 * scale);
lift(1);
break;
case 3:
drawTo(bx + 2 * scale, by + 17 * scale);
lift(0);
bogenUZS(bx + 5 * scale, by + 15 * scale, 5 * scale, 3, -2, 1);
bogenUZS(bx + 5 * scale, by + 5 * scale, 5 * scale, 1.57, -3, 1);
lift(1);
break;
case 4:
drawTo(bx + 10 * scale, by + 0 * scale);
lift(0);
drawTo(bx + 10 * scale, by + 20 * scale);
drawTo(bx + 4 * scale, by + 2 * scale); // drawTo(bx + 2 * scale, by + 6 * scale);
drawTo(bx + 15 * scale, by + 6 * scale);// drawTo(bx + 12 * scale, by + 6 * scale);
lift(1);
break;
case 5:
drawTo(bx + 2 * scale, by + 5 * scale);
lift(0);
bogenGZS(bx + 5 * scale, by + 6 * scale, 6 * scale, -2.5, 2, 1);
drawTo(bx + 5 * scale, by + 20 * scale);
drawTo(bx + 12 * scale, by + 20 * scale);
lift(1);
break;
case 6:
drawTo(bx + 2 * scale, by + 10 * scale);
lift(0);
bogenUZS(bx + 7 * scale, by + 6 * scale, 6 * scale, 2, -4.4, 1);
drawTo(bx + 11 * scale, by + 20 * scale);
lift(1);
break;
case 7:
drawTo(bx + 2 * scale, by + 20 * scale);
lift(0);
drawTo(bx + 12 * scale, by + 20 * scale);
drawTo(bx + 2 * scale, by + 0);
lift(1);
break;
case 8:
drawTo(bx + 5 * scale, by + 10 * scale);
lift(0);
bogenUZS(bx + 5 * scale, by + 15 * scale, 5 * scale, 4.7, -1.6, 1);
bogenGZS(bx + 5 * scale, by + 5 * scale, 5 * scale, -4.7, 2, 1);
lift(1);
break;
case 9:
drawTo(bx + 9 * scale, by + 11 * scale);
lift(0);
bogenUZS(bx + 7 * scale, by + 15 * scale, 5 * scale, 4, -0.5, 1);
drawTo(bx + 5 * scale, by + 0);
lift(1);
break;
case 111:
lift(0);
drawTo(rubberx, rubbery);
drawTo(58, 42);drawTo(58, 45);
drawTo(0, 45);
drawTo(0, 41);
drawTo(58, 41);
drawTo(60, 37);drawTo(0, 37);
drawTo(0, 33);
drawTo(60, 33);
drawTo(60, 29);drawTo(0, 29);
drawTo(0, 25);
drawTo(60, 25);
drawTo(60, 20);drawTo(0, 20);drawTo(60, rubbery-3);
drawTo(rubberx+6 , rubbery-3);
lift(2);
drawTo(rubberx , rubbery);
break;
case 11:
drawTo(bx + 5 * scale, by + 15 * scale);
lift(0);
bogenGZS(bx + 5 * scale, by + 15 * scale, 0.1 * scale, 1, -1, 1);
lift(1);
drawTo(bx + 5 * scale, by + 5 * scale);
lift(0);
bogenGZS(bx + 5 * scale, by + 5 * scale, 0.1 * scale, 1, -1, 1);
lift(1);
break;
}
}
//抬函数,不同的摆臂高度
void lift(char lift) {
switch (lift) {
// room to optimize !
case 0:
if (servoLift >= LIFT0) {
while (servoLift >= LIFT0)
{
servoLift–;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT0) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
break;
case 1:
if (servoLift >= LIFT1) {
while (servoLift >= LIFT1) {
servoLift–;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT1) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
break;
case 2:
if (servoLift >= LIFT2) {
while (servoLift >= LIFT2) {
servoLift–;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
else {
while (servoLift <= LIFT2) {
servoLift++;
servo1.writeMicroseconds(servoLift);
delayMicroseconds(LIFTSPEED);
}
}
break;
}
}
//勾股定理
void bogenUZS(float bx, float by, float radius, int start, int ende, float sqee) {
float inkr = -0.05;
float count = 0;
do {
drawTo(sqee * radius * cos(start + count) + bx,
radius * sin(start + count) + by);
count += inkr;
}
while ((start + count) > ende);
}
//cos?sin?
void bogenGZS(float bx, float by, float radius, int start, int ende, float sqee) {
float inkr = 0.05;
float count = 0;
do {
drawTo(sqee * radius * cos(start + count) + bx,
radius * sin(start + count) + by);
count += inkr;
}
while ((start + count) <= ende);
}
void drawTo(double pX, double pY) {
double dx, dy, c;
int i;
// dx dy of new point
dx = pX - lastX;
dy = pY - lastY;
//path lenght in mm, times 4 equals 4 steps per mm
c = floor(4 * sqrt(dx * dx + dy * dy));
if (c < 1) c = 1;
for (i = 0; i <= c; i++) {
// draw line point by point
set_XY(lastX + (i * dx / c), lastY + (i * dy / c));
}
lastX = pX;
lastY = pY;
}
double return_angle(double a, double b, double c) {
// cosine rule for angle between c and a
return acos((a * a + c * c - b * b) / (2 * a * c));
}
//用各种三角函数把位置坐标换算成舵机的角度,具体咋算的,请参考
//Plotclock by joo - Thingiverse
//http://www.thingiverse.com/thing:248009/
void set_XY(double Tx, double Ty)
{
delay(1);
double dx, dy, c, a1, a2, Hx, Hy;
// calculate triangle between pen, servoLeft and arm joint
// cartesian dx/dy
dx = Tx - O1X;
dy = Ty - O1Y;
// polar lemgth © and angle (a1)
c = sqrt(dx * dx + dy * dy); //
a1 = atan2(dy, dx); //
a2 = return_angle(L1, L2, c);
servo2.writeMicroseconds(floor(((a2 + a1 - M_PI) * SERVOFAKTORLEFT) + SERVOLEFTNULL));
// calculate joinr arm point for triangle of the right servo arm
a2 = return_angle(L2, L1, c);
Hx = Tx + L3 * cos((a1 - a2 + 0.621) + M_PI); //36,5掳
Hy = Ty + L3 * sin((a1 - a2 + 0.621) + M_PI);
// calculate triangle between pen joint, servoRight and arm joint
dx = Hx - O2X;
dy = Hy - O2Y;
c = sqrt(dx * dx + dy * dy);
a1 = atan2(dy, dx);
a2 = return_angle(L1, (L2 - L3), c);
servo3.writeMicroseconds(floor(((a1 - a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));
}
致 谢
本次毕业设计,我首先要感谢我的指导老师沈洪洋老师和台闯老师的在他们的耐心指导下,我能够顺利的完成毕业设计,虽然平日里沈老师工作繁多,但在我做毕业设计的每个阶段,从外出实习到查阅资料,设计草案的确定和修改,中期检查,后期详细设计等整个过程中都给予了我悉心的指导。由于我的设计不算简单,所以在整个过程中也犯了很多错误,沈老师能够细心地帮我指正。除此之外,台老师的专业水准让我崇敬,他的治学严谨和科学研究的精神也是我永远学习的榜样,而且在我完成设计的同时教给我很多新知识,并告诉我如何应用于实践。同时还要感谢我的同学们,在写论文的过程中我们互帮互助,不仅完成了论文也培养了团结互助的风气。
回首一年以来的岁月,老师们精心指导我,同时也对我的实习工作提出了一些宝贵的建议,告诉我如何把学会的知识应用到生活当中去,如何严谨认真地完成一项工作,如何耐心细心地面对困难,他们严肃的科学态度,严谨的治学精神,精益求精的工作作风,深深地感染和激励着我。从课题的选择到项目的最终完成,二位老师都始终给予我细心的指导和不懈的支持。在此谨向二位老师致以诚挚的谢意和崇高的敬意。
从论文开题到如今的完成,我真心的感谢每一位指导过我的老师,每一位在学习上给过我帮助的同学,在你们看来可能是举手之劳,但是在我看来却是你们给予我的宝贵财富,在这里请接受我诚挚的谢意!最后我还要感谢培养我长大含辛茹苦的父母,谢谢你们!