查看:
21159
回复: 25 |
开源作品参赛《进化传说 -- 上古蜥蜴》
|
|
发表于2017-06-17 18:01:28
|
显示全部楼层
1#
电梯直达
【报名阶段需要填写的内容】 1. 参赛者姓名(必填项): 王锦迪 2. 单位或学校名称(必填项): 南京亨乾电子科技有限公司 3. 当前职务或职称(必填项): 工程师 4. 参赛作品的名字(必填项): 进化传说 -- 上古蜥蜴 5. 简要陈述您的idea和作品(必填项): 1)总体结构为履带底盘,电机及驱动电路,摄像头等。 2)控制结构包括树莓派运行上层软件SPI,stm32底层控制,另外包含电机驱动、供电控制等电路。STM32与树莓派通过SPI连接用于下传命令、上传状态。 3)软件包括速度控制、图像处理等 目前实现的内容包括:履带底盘的机械结构部分的设计及实物3D打印、组装调试;电机及驱动电路的调试;STM32 通过PWM调节电机转速;PID算法的调试;树莓派环境的搭建,包括SPI通讯测试、程序控制摄像头的测试、机器学习框架Tensorflow的安装;目前可以在树莓派上用Python程序通过SPI通讯给STM32发送命令,控制履带底盘的转速。 6. 拟用到的立创商城在售物料(必填项): 树莓派及摄像头,stm32芯片,电机驱动相关芯片,外围杂项元器件 7. 拟用到的非立创商城物料或其它补充(必填项): 电机、轴承、弹簧、螺丝等。stm32开发板。本项目结构件大量采用3D打印,使用自购3D打印机。 【作品正式发表(报名成功后进入设计阶段)需要填写的内容】 第一章 楔子 不知你是否和我一样,在生命的某个阶段,如此强烈地希望自己的生活中会有一段插曲是变形金刚,或者是终结者。当我们终于能够吃饱穿暖、事业稳定,你会不会也像我一样,有时会无意中记起,小时候曾经在旧物摊上寻觅钟表的齿轮,希望能拼成一个玩具小车。
蜥蜴项目的初始目标就是延续小时候的梦想,不同的是,现在我们有了更强的能力。凭借专业领域的长久学习和实践经验,将能够实现一个更强大、更灵活的大玩具。更诱人的是,凭借我们的学习能力,蜥蜴将会不断地改进,越来越强大,如同进化的传说。
蜥蜴项目将作为一个开源项目长期存在,原型版完成之后将针对各环节进行优化以及增加新功能。电路图、PCB、sldprt、stl文档、单片机和树莓派的源代码都会保持公开和更新。
可以先看一下视频,https://v.qq.com/x/page/f0540dnaye1.html 前进的命令由PC机通过WiFi连接树莓派发出,树莓派的程序随后通过SPI通讯给STM32单片机发出命令,STM32采用PID算法驱动履带电机。目前小车重心在后面,后轮遇到障碍时,动力不足以越过,PID算法自动调整驱动功率,越过障碍。
第二章 原始生物的运动器官 蜥蜴算是比较大型的项目,从最开始就计划按不同部分分帖讨论。第一帖在这里: http://club.szlcsc.com/article/details_7855_1.html 其中有详细的设计思考过程,因为计划是个长期项目,设计文件也是随进度更新,都在帖子里。
部分外购零部件:
DNA片段 -- 机械结构部分设计图:
蜥蜴的脚趾? -- 零部件组装:
这应该算是完整的四肢了吧 -- 底盘及电机负重图 :
到这一部分为止的演示视频,用外接12V直接接电机:https://v.qq.com/x/page/s0540u1rlfv.html 这个视频直观演示底盘悬挂结构的负重、缓冲、动态分担负载的性能,比起网上动辄上千元还不带缓冲结构的底盘,也算不枉我花费大量时间从头学习研究设计一直到把它做出来。 第三章 从末梢神经到脊髓 -- 电机测速、调速、PWM驱动、PID驱动
想想蜥蜴的神经系统还挺专业,因为它分神经组织和神经信号两部分。其实电路的硬件就相当于生物的神经组织,而神经信号当然就是相应的软件和电路信号了。 在蜥蜴项目的最初规划阶段曾经明确过一个原则:尽量避免重新造轮子。按这一原则,在使用单片机的时候我毫不犹豫地选择了开发板--压在箱子底、放在阁楼上、落满灰尘,但是仍然好用的野火STM32开发板。
电路硬件其实很简单,单片机本身能用到的几乎就是个最小系统,电机测速的霍尔传感器可以用3.3V电源,这样信号也是3.3V,可以直接接单片机。电机驱动电路L9110也可以使用3.3V输入而给电机供应12V的电压。这样简单的数字信号,直接用杜邦线连接就可以了。
电机需要12V电源,采用TPS60188升压。电源电路对抗干扰要求高,况且60188的封装也没法手工焊,在立创做了样板 蜥蜴作为一个“动物”,肯定要用个移动电源,TP5602是不错的选择,3A充放电,各种保护。。。广告时间到!购买链接 http://www.szlcsc.com/product/details_81512.html 但是在调试过程中,电池电量耗费很快,充电则太耽误时间,所以调试还是用AC-DC的电源模块供电,谁让咱就是做这个的呢,从桌子底下翻出来两个就好了。
程序没有太多可说的,大部分是相应外设的初始化及控制、读取 把所有函数折叠一下,便于看个总貌:
直接对电机作用的是PWM信号。PID控制算法也需要将PWM占空比作为直接的被控对象,因此PWM是电机驱动的基础,首先完成的是PWM的软硬件调试: 需要改变某个通道的占空比时,只需要修改一个寄存器TIM2->CCRx就可以了。
// TIM2作为pwm输出,4个通道用于驱动两个履带电机正反转。引脚为23、24、25、26,即PA0、1、2、3, void PWM_User_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; u16 init_CCR1_Val = 0; // 占空比 = (此变量/ (TIM_Period+1))* 100%,TIM_Period这里设为9999 // ....................... 引脚功能初始化 .................. /*GPIOA Configuration: TIM2 channel 1 and 2 as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //.......................TIM2 Time base.............................. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ; //设置时钟分频系数:不分频 TIM_TimeBaseStructure.TIM_Prescaler = 36; //设置预分频,分频后为 2MHz TIM_TimeBaseStructure.TIM_Period = 9999; //当定时器从0计数到9999,即为10000次,为一个定时周期,即频率200Hz TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //........................... 各通道 ................................. // 通道1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = init_CCR1_Val; //设置跳变值,当计数器计数到这个值时,电平发生跳变 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //当定时器计数值小于CCR1_Val时为高电平 TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); // 通道2 TIM_OC2Init(TIM2, &TIM_OCInitStructure); //使能通道2 TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); // 通道3 TIM_OC3Init(TIM2, &TIM_OCInitStructure); //使能通道3 TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); // 通道4 TIM_OC4Init(TIM2, &TIM_OCInitStructure); //使能通道4 TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable); //................................................................ TIM_ARRPreloadConfig(TIM2, ENABLE); // 使能TIM2重载寄存器ARR TIM_Cmd(TIM2, ENABLE); //使能定时器2 } PID控制 PWM是最简单的开环调速,仔细想想还不如自然界的蜥蜴,蜥蜴的行为毕竟还是闭环反馈的。一般来说,闭环控制总是必不可少的。闭环控制中,PID属于用得比较多也比较简单的了,当然性能也就是差强人意。不过好在蜥蜴项目的重点不是放在这方面,说得过去就行了。 在我的第二贴里, http://club.szlcsc.com/article/details_7856_1_8.html#floor_8 这里对PID算法做了简要的解说, 自我感觉还是很容易懂的,不熟悉的朋友可以去看看。应该加个醒目的标题什么的,最近两天时间太紧了,当时好长的文本,写完就忽略了标题的问题,要改的时候已经晚了不能改了。看起来好像是一大堆废话一样。。。 PID的核心算法其实很简单,就这么一点代码。在上面提到那个帖子里,有其他辅助的内容,包括结构的定义、具体参数值、定时计算的机制等
err1 = Mot1PIDData.HallSetValue - Mot1HallTotal; // 设定值 减 霍尔传感器在上次刷新周期内(100mS)的计数值 记为 err Mot1PIDData.LastErr = Mot1PIDData.CurErr; // 用当前误差替代上次误差 Mot1PIDData.CurErr = err1; // 更新当前误差 Mot1PIDData.SigmaErrBefore = Mot1PIDData.SigmaErrBefore * 3 / 4 + err1; //对误差历史逐次衰减 u16deltaPulse = Mot1PIDData.KP * err1 + // 需要修正的值 等于 P、I、D 三项分别乘系数之后求和。 即 KP * err + Mot1PIDData.KD * (Mot1PIDData.CurErr - Mot1PIDData.LastErr) + // ( 当前误差 减 上次误差 ) / 计数周期 近似为微分 KD * DeltaErr + Mot1PIDData.KI * Mot1PIDData.SigmaErrBefore; // 近似历史积分(改进型) KI * SigmaErr Mot1PIDData.DeltaPWM = u16deltaPulse / HALL_CNT_MAX; // 计算出来的脉冲修正值 / 可能的最大值 * 100 = PWM的0-99范围; 三个K值是乘以100的,此处要除以100,所以- if(Mot1PIDData.Clockwise == 1) // 如果电机1当前正转 ch = 1; else ch = 2; i16t = Mot1PIDData.CurrentPWM; i16t += Mot1PIDData.DeltaPWM; if(i16t >= 100) i16t = 99; if(i16t < 0) i16t = 0; PWM_SetMotorSpeed(ch,i16t ); PID运行演示视频 https://v.qq.com/x/page/x0540pae5xw.html 视频中,PID的参数采用楼上图片中的参数,可以看到明显的PID调整的特点。两次手握住履带后,电机受到阻力立刻减速,然后由于PID算法的作用,PWM占空比增加,履带又顽强地开始加速到目标速度,此时占空比很大,履带底盘在泡沫的架子上咔哒咔哒乱动,尤其第二次更明显。 由于占空比很大,突然松手履带就会转得很快,此时PID调节再次起作用,速度迅速降低,然而存在超调现象,也就是速度降低到预设速度之后并没有停止下降,而是继续减慢。然后又在算法调整下慢慢逼近设定值,这就是超调现象。超调的成因,固然是PID参数(也就是Kp、Ki、Kd)需要精细调整,但是,PID算法很难在大范围内保持良好的性能,例如在负载变化很大的情况下兼顾调节速度与超调量。如果需要更好的性能,需要更“高端”的控制理论 SPI通讯 树莓派只有一个串口,分配给了蓝牙。虽然也可以用作串口,但是那样以后就注定用不成蓝牙了。和单片机通讯,SPI也是可选项之一。 SPI的一个特点就是他是同步通信。这意味着需要一个时钟信号来为双方提供同步,而这又意味着,只有主机主动给出时钟信号,从机才能发送数据;主机的时钟信号一停,丛机的发送过程就中断。尽管主机的时钟信号一般不会突然停止,但是从机收到主机数据后需要时间来处理,很难保证立刻就开始发送应答数据。所以在SPI通讯中,从机最好是预先准备好数据,而主机发送完数据后,要继续发送无意义的字符以便保持时钟信号不会停止,这样才能收到从机的应答。 对于单片机来说,SPI有不少参数要指定。通讯双方的参数要保持一致。 下面这段程序只给出了STM32的SPI参数配置,没有包括引脚分配、中断设置等。
///////////////////////// SPI参数配置 //////////////////////////////// // W25X16: data input on the DIO pin is sampled on the rising edge of the CLK. // Data on the DO and DIO pins are clocked out on the falling edge of CLK. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); /* Enable SPI1 */ SPI_Cmd(SPI1, ENABLE); 第四章 原始的眼睛和大脑 -- 树莓派
树莓派软硬件简单介绍 树莓派是国外的一款“开源”的处理模块(带引号是他的主控芯片是专供的,你自己没办法做出来),主要特性包括:主频1.2G,内存1G,带WiFi,四个USB口可外接键盘鼠标,带HDMI口可外接显示器,一堆引出的IO脚,可以运行Linux等图形操作系统。 有人说树莓派比起同样性能的其他模块价格贵,但是它同样有一个压倒性的优势,就是广泛流行带来的大量的资料和社区探讨。基本上,需要用到的东西在网上都很容易找到。 出于科普的目的,树莓派的官方系统(基于Debian)中集成了很多编程工具,对Python也有编译环境。我们采用Python作为开发语言。说实话,个人觉得Python是个大坑,到处充斥着奇技淫巧,一个数组能变化出成千上万的操作方法,初看起来很容易看懂,但是如果要精确写出来,尤其是要想看到别人的程序能精确知道是什么结果,好像比C语言要记的东西多多了。奈何,现在主流的各种工具都提供对Python的支持,像机器学习框架Tensorflow,就明确说有些功能在C语言的库里没有实现。我们也就只好跳进这个大坑了。 树莓派的摄像头 有一个库是专门给树莓派的摄像头做的,叫做picamera(这个库在电脑的Linux系统下是运行不了的) 使用picamera,可以轻易地控制树莓派的摄像头:
import time as tm import picamera #摄像头初始化 cam = picamera.PiCamera() cam.resolution = (128,112) #下面四行用于验证摄像头正常工作。preview可以在命令行运行,但是预览画面很难关掉,最好在程序中用stop_preview cam.start_preview() #开始播放预览画面 tm.sleep(2) cam.stop_preview() #停止预览 cam.capture('ff.jpg') #拍照并保存到文件,记得说“茄子” 更强大的是,可以直接把图像数据保存到numpy数组里(我用的是Python2.7,需要提供一个一维数组,Python3对应的库则用三维数组)
import numpy as np RawImageData = np.empty((128*112*3),dtype=np.uint8) #准备数组 cam.capture(RawImageData,'rgb') #采集图像 机器学习框架 Tensorflow Tensorflow是谷歌的开源机器学习框架。框架的含义个人理解包含两层,一层是库。你要什么功能,就调用相应的函数。第二层意思是,这种库不能完全随意调用,要符合一定顺序,这个顺序是它背后实现的内在机制决定的。这个机制的主要部分就是计算图,你总要把图画好,然后才能开始计算。Tensorflow在背后帮你实现了这些东西,你只要对“业务逻辑”进行编程就可以了,大大提高了你的劳动效率。 大概这么简单个小程序可以完成一个最简单的神经网络的构建、训练、结果输出。主要步骤是定义数据、定义loss、定义优化方法,然后初始化框架,最后就可以慢慢算了
树莓派的SPI 树莓派自带一个SPI的Python库,叫做spidev。 对SPI的初始化:
import spidev spi = spidev.SpiDev() spi.open(0,0) spi.mode = 3 spi.max_speed_hz = 30000 SPI向下位机传送命令:
print spi.xfer([0x55,2,50,50,0,0,0]) 这条命令和前面的stm32的spi程序配合,向其传送命令,让左右履带电机都以50%的速度运行。视频中演示的动作就由这条命令来完成。同时将STM32返回的数据(100mS内测速脉冲读数值)显示出来。 临时的第五章 临时的milestone
本来有了前面这些东西,基本就可以实现一些最简单的功能了,比如循迹小车,几乎是呼之欲出了。奈何一来时间紧,要赚钱养家,截止日期前这一段时间刚好工作上又比较忙,二来,简单的循迹小车也不是蜥蜴项目的目的。但是,花了这么多的时间精力,总归还是有些收获,可以总结点心得的。 从最基础的底盘的机构可以说明,在纯电子行业,借助3D打印这类快速成型技术,可以实现一些简单、精度要求不高的机械机构。这些机械机构可以是工作上的工具,可以是家里的实用物件,也可以是小朋友的玩具。这些东西甚至不一定是很简陋的。就蜥蜴的悬挂来说,其负重、缓冲、一对负重轮负载均衡的性能应该说远好于模型和玩具的级别。如果做成金属的,应该完全可以进入专业领域。 就电子和控制算法来说,PID是最常用的调速算法之一,直流电机的PWM驱动也是小功率场合低成本、常用解决方案。而树莓派这一可以运行操作系统的模块,以及可以通过WiFi与PC机相连,则为“大脑”的实现提供了广阔的空间,即使拿目前的蜥蜴,去实现“走走看看,你在电脑前远程监视”这样的功能,也是十分简单的(网上有现成的文章)。
临时的milestone是为了给竞赛一份答卷,未来,蜥蜴将会不断完善,真正演绎一段进化的传说
|
|
发表于2017-06-29 09:24:52
|
显示全部楼层
11#
名字好流弊啊,也是个小说爱好者啊。记得把文字排版好一点,蓝色衬底的字看不清是什么字,把字体调成白色吧
|
|