实现球板控制系统——基于openmv视觉处理+stm32主控

最近在着手准备全国大学生电子设计竞赛,于是就找往年的赛题作为练习。这一次我选的是17年电赛的题目——滚球控制系统,要求在一定的时间内对板子上的球位置进行控制,我做出来的效果如下图所示。


接下来就分享我从拿到试题到完成的过程。

1.分析赛题选型


首先阅题要仔细,阅读题目后第一件事就是要如何去实现基本要求。控制量是什么?结果是什么?可以采用什么方案?在这里我第一件事就是把方形板切割出来,我采用的是亚克力材料,也可以用雪费板。质量不要太重也不要太轻。这时候就要思考了,题目无非就是要我们控制小球在板子上面的坐标,这就有了两种方案:1.触摸板定位。2.使用视觉定位。在这里我选用了视觉定位,因为身边有openmv。然后就是我们做控制必不可少的电机选型了。这一次无疑要选用舵机了,因为舵机能精准控制角度。主控的话我选用stm32f103rc系列,因为题目无非就是两个舵机和串口,使用这类芯片不会造成资源浪费,主频有48m完全够用

这里我补充说明一个点就是视觉检测选用白板黑球还是使用黑板白球。经过我的实测,选用白板黑球的话对于识别不太有利的,因为灯光照在黑球上面会反光,以及周围太多黑色的物体对识别产生噪点了(比如影子)。所以下面我搭建机械结构的时候选用了白球,并且用黑色自动喷漆把板子喷成了黑色,这样识别效果非常好。

2.结构搭建

这一个步骤是整道题目最关键的地方了,可以说是控制半壁江山。结构搭得好,代母就很好调很容易完成要求。要是结构搭建不好,软件代码怎么写都没用。

首先给舵机装上舵机臂,让力矩可以传输出去。然后使用轴承把舵机臂与双文螺杆进行连接,然后用金属球头把双头螺杆与板子连接在一起(此处看不懂名字的可以直接去淘宝搜索)。这里结构搭建的要点是:1.舵机能顺利地把力矩转化成板子xy方向的转动,使得通过不哦那个角度的转动控制球的位置(原理和用乒乓球拍控制兵乓球一样)2.舵机上电的时候会瞎转,你要保证做好硬件防护措施,使得机械结构以及舵机不会因为舵机瞎转而破坏掉。


然后就是在板子的上方找位置固定openmv,固定前连接上电脑,使得能够拍摄到整块板子。

最后就是主控板了,我选用了一块我之前话的板子,上面有两个舵机接口引出,一个串口引出以及用于查看运行信息的oled接口。上面白色座子我是用来接无线调试器的,在这里我非常建议做控制的同学拥有一个自己的无线调试器,因为我们做控制要经常进行调参,代码经常编译下载,采用无线调试器能够在下载代码后马上观测现象而不用老是拔插调试器。

3.代码实现与pid调试

首先是openmv的代码,需要实现的功能是识别小球并且把小球的坐标通过串口发送出去,这里再调试的时候可以用ch340模块接到电脑用串口调试助手查看输出数据。

# Blob Detection and uart transport
import sensor, image, time
from pyb import UART
import json
# For color tracking to work really well you should ideally be in a very, very,
# very, controlled enviroment where the lighting is constant...
yellow_threshold   = (79, 100, -7, 6, 4, 41)
# You may need to tweak the above settings for tracking green things...
# Select an area in the Framebuffer to copy the color settings.sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # use RGB565.
sensor.set_framesize(sensor.QQVGA) # use QQVGA for speed.
sensor.skip_frames(10) # Let new settings take affect.
sensor.set_auto_whitebal(False) # turn this off.
clock = time.clock() # Tracks FPS.uart = UART(3, 115200)
def find_max(blobs):max_size=0for blob in blobs:if blob.pixels() > max_size:max_blob=blobmax_size = blob.pixels()return max_blobwhile(True):img = sensor.snapshot() # Take a picture and return the image.blobs = img.find_blobs([yellow_threshold])if blobs:max_blob=find_max(blobs)print('sum :', len(blobs))img.draw_rectangle(max_blob.rect())img.draw_cross(max_blob.cx(), max_blob.cy())output_str="[%d,%d]" % (max_blob.cx(),max_blob.cy()) #方式1#output_str=json.dumps([max_blob.cx(),max_blob.cy()]) #方式2print('you send:',output_str)uart.write(output_str+'\r\n')else:print('not found!')

不会使用openmv的建议看一下openmv入门

上面代码的yellow_threshold要填写小球的lab数值,需要通过openmvIDE直接测出来填写。
然后就是数据处理了,因为通过串口传输的数据都是字符串类型的,要进行坐标控制需要的是数值信息,所以需要自己写函数转化一下:

if(USART3_RX_STA&0x8000){u8 x=0,y=0,z=0;      len=USART3_RX_STA&0x3fff;//µÃµ½´Ë´Î½ÓÊÕµ½µÄÊý¾Ý³¤¶È//printf("\r\nÄú·¢Ë͵ÄÏûϢΪ:\r\n");for(t =0;t<len;t++){USART3->DR=USART3_RX_BUF[t];while((USART3->SR&0X40)==0);//µÈ´ý·¢ËͽáÊøif(USART3_RX_BUF[t]=='[')x=1,y=0;if(USART3_RX_BUF[t]==','){x=0,y=1;xx[t-1]='\0';} if(USART3_RX_BUF[t]==']'){yy[z]='\0';x=0,y=0,z=0;};if(x==1&&USART3_RX_BUF[t]!='[')xx[t-1] = USART3_RX_BUF[t];if(y==1&&USART3_RX_BUF[t]!=','){yy[z] = USART3_RX_BUF[t]; z++;};}for(t=0;t<2;t++){USART3->DR=USART3LAST[t];while((USART3->SR&0X40)==0);//µÈ´ý·¢ËͽáÊø}//        printf("\r\n\r\n");//²åÈë»»ÐÐXt=atoi(&xx[0]);Yt=atoi(&yy[0]);OLED_ShowNum(0,52,Yt,3,12);OLED_ShowNum(64,52,Xt,3,12);//      OLED_Refresh_Gram();stop=0;USART3_RX_STA=0;}  if(stop>25){OLED_ShowString(0,0,"NOFOUND",24);OLED_Float(40,0,pitch,3);OLED_Refresh_Gram();control=0;}else{delay_ms(10);OLED_ShowString(0,0,"FINDTAG",24);mpu_dmp_get_data(&pitch,&roll,&yaw);
//          OLED_Float(40,0,pitch,3);
//          OLED_Float(40,64,roll,3);OLED_Refresh_Gram();control=1;}

这里是我再主函数循环里写的串口3接收函数,功能是接收openmv传输过来的xy坐标信息并且转化成整型类型的数值,把数字传送给舵机控制函数进行pid控制。参数control=1的时候就会进行pid调节,当openmv没有识别到小球的时候control=0。
最后就是pid控制函数了,他实现的功能就是通过小球坐标信息作为反馈,实时控制舵机转动而调节小球位置。

extern float Xt,Yt,pwmva,pwmvb;  //     1000=<pwmva<=2120   500=<pwmvb<=2500
float media=1340,medib=1380,max=100;
float X0=78,Y0=57,set=0;         //×ø±êÖÐÖµ
float kp=450,ki=0,kd=290;    //ˮƽÃæ·½Ïò
float kp2=450,ki2=0,kd2=290;  //ÊúÖ±·½Ïò
//float x1,y1,xdiffer,ydiffer,y1last,x1last;
float dia=0,dib=0;void pida(void)
{static float error,ierror,derror,errorlast;error=X0-Xt;ierror=ierror+error;derror=error-errorlast;errorlast=error;if(ierror>3000) ierror=3000;else if(ierror<-3000) ierror=-3000;dia=kp*error/100+ki*ierror+kd*derror/10;   //P:
//  if(dia>10) dia=10;
//  else if(dia<-10) dia=-10;
}void pidb(void)
{static float error,ierror,derror,errorlast;error=Y0-Yt;ierror=ierror+error;derror=error-errorlast;errorlast=error;if(ierror>3000) ierror=3000;else if(ierror<-3000) ierror=-3000;dib=kp2*error/100+ki2*ierror+kd2*derror/10;
}int absa(int a)
{   if(a<media-max)pwmva=media-max;    //×ó±ß                  //1330if(a>media+max)pwmva=media+max;      //ÓÒ±ßreturn pwmva;
}int absb(int b)
{if(b<medib-max)pwmvb=medib-max;   //1380if(b>medib+max)pwmvb=medib+max;      return pwmvb;
}void setpwm(void)
{pwmva=media+dia;pwmvb=medib-dib;TIM_SetCompare3(TIM3,absb(pwmvb));TIM_SetCompare4(TIM3,absa(pwmva));
}void contro(void)
{pida();pidb();set=!set;if(set==1)setpwm();
}

pid参数整定的方法:因为舵机有两个xy方向,我们需要股东一个方向进行调节,一个方向成功后再换另一个方向。首先ki、kd设为0.调节kp使得小球再中间位置震荡,然后调节kd使得小球稳定,最后可以加ki进行修饰,也可以不加。最后实现的效果是再任意点投放小球,系统都能够在短时间内将小球稳定到板子中心。到了这里就大功告成了,题目的其他要求就显得很简单了,只要我把中值坐标X0、Y0进行动态的调节,小球就能按照要求动起来。

滚球板球控制系统详解(openmv+stm32实现)相关推荐

  1. 滚球控制系统详解 —— (附核心代码)

    最近练习了17年的国赛题 -- 滚球控制系统 这里展示一下画圆: 观看完整视频点这里 接下来,我来分享一下从搭整体结构到调试完的过程. 这是我搭完的整体结构 (缩小版) (不管什么题,结构部分还是很重 ...

  2. SPI通讯协议详解 基于STM32

    SPI 协议简介 SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface),即串行外围设备接口,是 一种高速全双工的通信总线.它被广泛地使用在 ADC.L ...

  3. XPT2046触摸屏实验过程详解与STM32代码解析

    触摸屏的简介 触摸屏的控制 XPT2046芯片简介 1. XPT2046 的初始化 2. XPT2046 读取 X.Y 值 3. 物理坐标值的数据处理 学习目标: 1.复习 STM32 的硬件 SPI ...

  4. linux平台xpt2046驱动,XPT2046触摸屏实验过程详解与STM32代码解析

    1.XPT2046的初始化 XPT2046说起来其实就是一个AD转换器,所以它适合不需要什么初始化设置的,而具体的初始化其实也就是单片机IO的初始化和SPI的初始化. 这次STM32是使用SPI1来进 ...

  5. 【MATLAB】sphere 球曲面函数详解

    官方文档 画个球瞅瞅 直接看坐标 官方文档 首先看一下 sphere 的官方文档 sphere % sphere 函数用于生成单位球面的 x,y,z 的坐标,以用于 surf or mesh.默认生成 ...

  6. STM32开发实战:W25Q32JV SPI Flash详解

    STM32开发实战:W25Q32JV SPI Flash详解 在STM32单片机的应用中,使用SPI Flash能够有效地扩展程序和数据存储空间.W25Q32JV SPI Flash是一种常用的Fla ...

  7. 详解spring事务失效和回滚失败的场景

    详解spring事务失效和回滚失败的场景 详解spring事务失效和回滚失败的场景 前言 一 .事务不生效 1.访问权限问题 2. 方法用final修饰 3.方法的内部调用 3.1 新加一个Servi ...

  8. STM32定时器之预分频器详解

    STM32定时器(TIM)之预分频器(PSC)详解 在STM32的定时器中,预分频器(Prescaler-PSC)用来将定时器时钟源进行分频输出. 预分频器的值由寄存器TIMx_PSC设定,是一个16 ...

  9. I2C详解(3) I2C总线的规范以及用户手册(2) I2C其他的总线协议以及总线速度

    I2C详解(3) I2C总线的规范以及用户手册(2) I2C 其他的总线协议以及总线速度 I2C详解(1) 一文快速了解I2C的工作原理 I2C详解(2) I2C总线的规范以及用户手册(1) I2C ...

  10. GPIO 配置之ODR, BSRR, BRR 详解

    STM32 GPIO 配置之ODR, BSRR, BRR 详解 用stm32 的配置GPIO 来控制LED 显示状态,可用ODR,BSRR,BRR 直接来控制引脚输出状态. ODR寄存器可读可写:既能 ...

最新文章

  1. 第一篇随笔,通常都是内容空洞的。
  2. 1086 Tree Traversals Again (25 分)【一般 / 建树 树的遍历】
  3. 手把手教你如何优化C语言程序
  4. 中兴通讯徐子阳:不破不立 用“加减乘除”建理想5G
  5. XSSFWorkbook 设置单元格样式_如何设置Excel单元格才能只输入数字!
  6. 基于springboot框架的java学生管理系统
  7. css 修改文字基准线_css外部样式表怎么写
  8. 【Luogu1996】约瑟夫问题(模拟,解法汇总)
  9. vue鼠标移动上去提示_关于如何处理vue中鼠标悬停事件的详细说明
  10. magento xml配置详解(2)
  11. 如何去除Excel图表网格线?
  12. Wi-Fi 6 BSS着色和空间重用白皮书
  13. 1756冗余_冗余电源1756-PA75R
  14. XShell远程登录华为云服务器
  15. 网络云盘前端项目启动
  16. 网络初级 关于ensp动态路由rip协议
  17. 电脑突然连不上WIFI和以太网
  18. 【Java攻城狮宝典】04-for循环(答案)
  19. OpenCV从摄像头中检测人脸
  20. find ? find !

热门文章

  1. 如何从零创造一个围棋AI
  2. 《IDSSIM:基于改进的疾病语义相似度方法的lncRNA功能相似度计算模型》论文梳理
  3. jQuery 插件——免费版
  4. 电脑网络异常故障解决办法
  5. 牛顿法 泰勒二次展开式
  6. 电赛 电容触摸串口屏
  7. 51单片机延时程序的理解
  8. 机器学习笔记一. 特征工程
  9. 机房环境监控报警系统
  10. 测试用例方法错误推测法