版本协议

BSD

标签
标准版
#第二届立创大赛#开源作品参赛《进化传说 -- 上古蜥蜴》

创建时间:5年前

项目主题:自拟主题

2908 3

描述

<p><span style="font-size: 24px;">第一章 楔子</span></p> <p> </p> <div>    不知你是否和我一样,在生命的某个阶段,如此强烈地希望自己的生活中会有一段插曲是变形金刚,或者是终结者。当我们终于能够吃饱穿暖、事业稳定,你会不会也像我一样,有时会无意中记起,小时候曾经在旧物摊上寻觅钟表的齿轮,希望能拼成一个玩具小车。</div> <div> </div> <div>    蜥蜴项目的初始目标就是延续小时候的梦想,不同的是,现在我们有了更强的能力。凭借专业领域的长久学习和实践经验,将能够实现一个更强大、更灵活的大玩具。更诱人的是,凭借我们的学习能力,蜥蜴将会不断地改进,越来越强大,如同进化的传说。</div> <div> </div> <div>    蜥蜴项目将作为一个开源项目长期存在,原型版完成之后将针对各环节进行优化以及增加新功能。电路图、PCB、sldprt、stl文档、单片机和树莓派的源代码都会保持公开和更新。</div> <div> </div> <p><img src="//image.lceda.cn/pullimage/IXkuGCMNXwp2y39aoYaUmqsi64s8ocOFkhl60MiP.jpeg" alt="" width="1024" height="768"></p> <p> <img title="点击查看大图" src="//" alt=""></p> <p> </p> <p>    可以先看一下视频,<a href="https://v.qq.com/x/page/f0540dnaye1.html" target="_blank">https://v.qq.com/x/page/f0540dnaye1.html</a></p> <p>    前进的命令由PC机通过WiFi连接树莓派发出,树莓派的程序随后通过SPI通讯给STM32单片机发出命令,STM32采用PID算法驱动履带电机。目前小车重心在后面,后轮遇到障碍时,动力不足以越过,PID算法自动调整驱动功率,越过障碍。</p> <p> </p> <p><span style="font-size: 24px;">第二章  原始生物的运动器官</span></p> <p>    蜥蜴算是比较大型的项目,从最开始就计划按不同部分分帖讨论。第一帖在这里: <a href="http://club.szlcsc.com/article/details_7855_1.html" target="_blank">http://club.szlcsc.com/article/details_7855_1.html</a></p> <p>    其中有详细的设计思考过程,因为计划是个长期项目,设计文件也是随进度更新,都在帖子里。</p> <p> </p> <p>部分外购零部件:</p> <p> <img src="//image.lceda.cn/pullimage/X4zfIeQDDIFt6D8xpoZ4QhSfl3uThOSuvoVzEOSu.jpeg" alt="" width="268" height="268"><img title="点击查看大图" src="//" alt=""></p> <p> </p> <p>DNA片段 -- 机械结构部分设计图:</p> <p> <img src="//image.lceda.cn/pullimage/0ttG3MeLcGK3BPA8gWpYAihWZYsrlxmXBAjeu0jG.jpeg" alt="" width="402" height="402"><img title="点击查看大图" src="//" alt=""></p> <p> </p> <p>蜥蜴的脚趾? -- 零部件组装:</p> <p> <img src="//image.lceda.cn/pullimage/yWrYZXPmmqaEt4Ru8dLrkdgY1qrq8BfokccJUWg6.jpeg" alt="" width="670" height="670"><img title="点击查看大图" src="//" alt=""></p> <p> </p> <p>这应该算是完整的四肢了吧 -- 底盘及电机负重图 :</p> <p><img title="点击查看大图" src="//" alt=""></p> <p><img src="//image.lceda.cn/pullimage/T30qP8rHblpb7ihrkjb0gUwFZERcu6iNITg1JDId.jpeg" alt=""></p> <p>    到这一部分为止的演示视频,用外接12V直接接电机:<a href="https://v.qq.com/x/page/s0540u1rlfv.html" target="_blank">https://v.qq.com/x/page/s0540u1rlfv.html</a></p> <p>    这个视频直观演示底盘悬挂结构的负重、缓冲、动态分担负载的性能,比起网上动辄上千元还不带缓冲结构的底盘,也算不枉我花费大量时间从头学习研究设计一直到把它做出来。</p> <p> </p> <p><span style="font-size: 24px;">第三章 从末梢神经到脊髓 -- 电机测速、调速、PWM驱动、PID驱动</span></p> <p> </p> <p>    想想蜥蜴的神经系统还挺专业,因为它分神经组织和神经信号两部分。其实电路的硬件就相当于生物的神经组织,而神经信号当然就是相应的软件和电路信号了。</p> <p>在蜥蜴项目的最初规划阶段曾经明确过一个原则:尽量避免重新造轮子。按这一原则,在使用单片机的时候我毫不犹豫地选择了开发板--压在箱子底、放在阁楼上、落满灰尘,但是仍然好用的野火STM32开发板。</p> <p> </p> <p>    电路硬件其实很简单,单片机本身能用到的几乎就是个最小系统,电机测速的霍尔传感器可以用3.3V电源,这样信号也是3.3V,可以直接接单片机。电机驱动电路L9110也可以使用3.3V输入而给电机供应12V的电压。这样简单的数字信号,直接用杜邦线连接就可以了。</p> <p> <img src="//image.lceda.cn/pullimage/twi6S2CsHfRmNL3FClRDaxc5fgTaXh3QAL1hb226.jpeg" alt="" width="665" height="665"><img title="点击查看大图" src="//" alt=""></p> <p> </p> <p>    电机需要12V电源,采用TPS60188升压。电源电路对抗干扰要求高,况且60188的封装也没法手工焊,在立创做了样板</p> <p> <img src="//image.lceda.cn/pullimage/Q9KhG6rGSys8uGwfTubBpkBcA1Pnxtq5ty05hLBb.jpeg" alt="" width="665" height="665"><img title="点击查看大图" src="//" alt=""></p> <p>    蜥蜴作为一个“动物”,肯定要用个移动电源,TP5602是不错的选择,3A充放电,各种保护。。。广告时间到!购买链接<a href="http://www.szlcsc.com/product/details_81512.html" target="_blank"> http://www.szlcsc.com/product/details_81512.html</a></p> <p>    但是在调试过程中,电池电量耗费很快,充电则太耽误时间,所以调试还是用AC-DC的电源模块供电,谁让咱就是做这个的呢,从桌子底下翻出来两个就好了。</p> <p> <img src="//image.lceda.cn/pullimage/bHSk6Wz0UaO4E1lj9pkv8yxiHd14A5Ohe0WbeaWR.jpeg" alt="" width="665" height="665"><img title="点击查看大图" src="//" alt=""></p> <p>    程序没有太多可说的,大部分是相应外设的初始化及控制、读取</p> <p>    把所有函数折叠一下,便于看个总貌:</p> <p> <img src="//image.lceda.cn/pullimage/fxIpuTsO7IcRlsr4QuriODtxmvZ7RYtJQcQPg7H6.jpeg" alt="" width="1002" height="476"><img title="点击查看大图" src="//" alt=""></p> <p>    直接对电机作用的是PWM信号。PID控制算法也需要将PWM占空比作为直接的被控对象,因此PWM是电机驱动的基础,首先完成的是PWM的软硬件调试:</p> <p>    需要改变某个通道的占空比时,只需要修改一个寄存器TIM2->CCRx就可以了。</p> <p> </p> <pre class="prettyprint lang-cpp">// 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 }    </pre> <p> </p> <p>PID控制</p> <p>    PWM是最简单的开环调速,仔细想想还不如自然界的蜥蜴,蜥蜴的行为毕竟还是闭环反馈的。一般来说,闭环控制总是必不可少的。闭环控制中,PID属于用得比较多也比较简单的了,当然性能也就是差强人意。不过好在蜥蜴项目的重点不是放在这方面,说得过去就行了。</p> <p>    在我的第二贴里, <a href="http://club.szlcsc.com/article/details_7856_1_8.html#floor_8" target="_blank">http://club.szlcsc.com/article/details_7856_1_8.html#floor_8</a> <strong>这里对PID算法做了简要的解说,</strong></p> <p>自我感觉还是很容易懂的,不熟悉的朋友可以去看看。应该加个醒目的标题什么的,最近两天时间太紧了,当时好长的文本,写完就忽略了标题的问题,要改的时候已经晚了不能改了。看起来好像是一大堆废话一样。。。</p> <p>    PID的核心算法其实很简单,就这么一点代码。在上面提到那个帖子里,有其他辅助的内容,包括结构的定义、具体参数值、定时计算的机制等</p> <p> </p> <pre class="prettyprint lang-cpp"> 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 ); </pre> <p>PID运行演示视频</p> <p><a href="https://v.qq.com/x/page/x0540pae5xw.html" target="_blank">https://v.qq.com/x/page/x0540pae5xw.html</a></p> <p> </p> <p>    视频中,PID的参数采用楼上图片中的参数,可以看到明显的PID调整的特点。两次手握住履带后,电机受到阻力立刻减速,然后由于PID算法的作用,PWM占空比增加,履带又顽强地开始加速到目标速度,此时占空比很大,履带底盘在泡沫的架子上咔哒咔哒乱动,尤其第二次更明显。</p> <p>    由于占空比很大,突然松手履带就会转得很快,此时PID调节再次起作用,速度迅速降低,然而存在超调现象,也就是速度降低到预设速度之后并没有停止下降,而是继续减慢。然后又在算法调整下慢慢逼近设定值,这就是超调现象。超调的成因,固然是PID参数(也就是Kp、Ki、Kd)需要精细调整,但是,PID算法很难在大范围内保持良好的性能,例如在负载变化很大的情况下兼顾调节速度与超调量。如果需要更好的性能,需要更“高端”的控制理论</p> <p> </p> <p> </p> <p>SPI通讯</p> <p>    树莓派只有一个串口,分配给了蓝牙。虽然也可以用作串口,但是那样以后就注定用不成蓝牙了。和单片机通讯,SPI也是可选项之一。</p> <p>    SPI的一个特点就是他是同步通信。这意味着需要一个时钟信号来为双方提供同步,而这又意味着,只有主机主动给出时钟信号,从机才能发送数据;主机的时钟信号一停,丛机的发送过程就中断。尽管主机的时钟信号一般不会突然停止,但是从机收到主机数据后需要时间来处理,很难保证立刻就开始发送应答数据。所以在SPI通讯中,从机最好是预先准备好数据,而主机发送完数据后,要继续发送无意义的字符以便保持时钟信号不会停止,这样才能收到从机的应答。</p> <p>    对于单片机来说,SPI有不少参数要指定。通讯双方的参数要保持一致。</p> <p>    下面这段程序只给出了STM32的SPI参数配置,没有包括引脚分配、中断设置等。</p> <p> </p> <pre class="prettyprint lang-cpp"> ///////////////////////// 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);</pre> <p> </p> <p><span style="font-size: 24px;">第四章 原始的眼睛和大脑 -- 树莓派</span></p> <p> </p> <p>树莓派软硬件简单介绍</p> <p>    树莓派是国外的一款“开源”的处理模块(带引号是他的主控芯片是专供的,你自己没办法做出来),主要特性包括:主频1.2G,内存1G,带WiFi,四个USB口可外接键盘鼠标,带HDMI口可外接显示器,一堆引出的IO脚,可以运行Linux等图形操作系统。</p> <p>    有人说树莓派比起同样性能的其他模块价格贵,但是它同样有一个压倒性的优势,就是广泛流行带来的大量的资料和社区探讨。基本上,需要用到的东西在网上都很容易找到。</p> <p>出于科普的目的,树莓派的官方系统(基于Debian)中集成了很多编程工具,对Python也有编译环境。<strong>我们采用Python作为开发语言。</strong>说实话,个人觉得Python是个大坑,到处充斥着奇技淫巧,一个数组能变化出成千上万的操作方法,初看起来很容易看懂,但是如果要精确写出来,尤其是要想看到别人的程序能精确知道是什么结果,好像比C语言要记的东西多多了。奈何,现在主流的各种工具都提供对Python的支持,像机器学习框架Tensorflow,就明确说有些功能在C语言的库里没有实现。我们也就只好跳进这个大坑了。</p> <p> </p> <p> </p> <p>树莓派的摄像头</p> <p>    有一个库是专门给树莓派的摄像头做的,叫做picamera(这个库在电脑的Linux系统下是运行不了的)</p> <p>    使用picamera,可以轻易地控制树莓派的摄像头:</p> <p> </p> <pre class="prettyprint lang-py">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') #拍照并保存到文件,记得说“茄子”</pre> <p> </p> <p>    更强大的是,可以直接把图像数据保存到numpy数组里(我用的是Python2.7,需要提供一个一维数组,Python3对应的库则用三维数组)</p> <p> </p> <pre class="prettyprint lang-py">import numpy as np RawImageData = np.empty((128*112*3),dtype=np.uint8) #准备数组 cam.capture(RawImageData,'rgb') #采集图像 </pre> <p> </p> <p>机器学习框架 Tensorflow</p> <p>    Tensorflow是谷歌的开源机器学习框架。框架的含义个人理解包含两层,一层是库。你要什么功能,就调用相应的函数。第二层意思是,这种库不能完全随意调用,要符合一定顺序,这个顺序是它背后实现的内在机制决定的。这个机制的主要部分就是计算图,你总要把图画好,然后才能开始计算。Tensorflow在背后帮你实现了这些东西,你只要对“业务逻辑”进行编程就可以了,大大提高了你的劳动效率。</p> <p><img src="//image.lceda.cn/pullimage/EKZfWIhoHmrz5jls9KqLGk5mhCbLdJ8lr76BLkG8.jpeg" alt="" width="412" height="483"><img title="点击查看大图" src="//" alt=""></p> <p>    大概这么简单个小程序可以完成一个最简单的神经网络的构建、训练、结果输出。主要步骤是定义数据、定义loss、定义优化方法,然后初始化框架,最后就可以慢慢算了</p> <p> </p> <p> </p> <p>树莓派的SPI</p> <p>    树莓派自带一个SPI的Python库,叫做spidev。</p> <p>    对SPI的初始化:</p> <p> </p> <pre class="prettyprint lang-py">import spidev spi = spidev.SpiDev() spi.open(0,0) spi.mode = 3 spi.max_speed_hz = 30000</pre> <p> </p> <p>    SPI向下位机传送命令:</p> <p> </p> <pre class="prettyprint lang-py">print spi.xfer([0x55,2,50,50,0,0,0]) </pre> <p> </p> <p>    这条命令和前面的stm32的spi程序配合,向其传送命令,让左右履带电机都以50%的速度运行。视频中演示的动作就由这条命令来完成。同时将STM32返回的数据(100mS内测速脉冲读数值)显示出来。</p> <div> </div> <div>临时的第五章 临时的milestone</div> <p> </p> <p>    本来有了前面这些东西,基本就可以实现一些最简单的功能了,比如循迹小车,几乎是呼之欲出了。奈何一来时间紧,要赚钱养家,截止日期前这一段时间刚好工作上又比较忙,二来,简单的循迹小车也不是蜥蜴项目的目的。但是,花了这么多的时间精力,总归还是有些收获,可以总结点心得的。</p> <p>    从最基础的底盘的机构可以说明,在纯电子行业,借助3D打印这类快速成型技术,可以实现一些简单、精度要求不高的机械机构。这些机械机构可以是工作上的工具,可以是家里的实用物件,也可以是小朋友的玩具。这些东西甚至不一定是很简陋的。就蜥蜴的悬挂来说,其负重、缓冲、一对负重轮负载均衡的性能应该说远好于模型和玩具的级别。如果做成金属的,应该完全可以进入专业领域。</p> <p>就电子和控制算法来说,PID是最常用的调速算法之一,直流电机的PWM驱动也是小功率场合低成本、常用解决方案。而树莓派这一可以运行操作系统的模块,以及可以通过WiFi与PC机相连,则为“大脑”的实现提供了广阔的空间,即使拿目前的蜥蜴,去实现“走走看看,你在电脑前远程监视”这样的功能,也是十分简单的(网上有现成的文章)。</p> <p> </p> <p>    临时的milestone是为了给竞赛一份答卷,未来,蜥蜴将会不断完善,真正演绎一段进化的传说。</p> <p> </p> <p> </p> <h3><strong>更多项目详情见链接:http://club.szlcsc.com/article/details_7053_1.html </strong></h3> <h3><strong>本项目归立创社区“风过琴弦”所有</strong></h3>

文档

BOM

暂无

附件

暂无

评论(0)

  • 表情
    emoji
    小嘉工作篇
    小嘉日常篇
  • 图片
成功
工程所有者当前已关闭评论
goToTop
svg-battery svg-battery-wifi svg-books svg-more svg-paste svg-pencil svg-plant svg-ruler svg-share svg-user svg-logo-cn svg-double-arrow