使用STM32和K210进行PID巡线,通过蓝牙模块与电脑通信进行P、I、D参数调节

目录

一.前言部分(废话部分)

二.K210色块识别

1.必要知识

2.色块识别

3.单片机的接收代码

三.通过蓝牙连接在电脑上实现PID的调参

一.前言部分(废话部分)

我使用的是HAL库,如果你使用的是标准库的话可以根据对应标准库的函数进行更改即可

因为之前使用灰度传感器进行巡线,即使用上PID,最后的效果也不尽人意,主要原因就在于传感器的传回的数字量是离散的,非常容易出现摇头、摆头的情况,原本打算再买一个有模拟量输出的传感器,突然又想到可以用实验室空下来的K210进行巡线,传回的数据也是一个类似模拟量的值,也就是连续的,于是就有了这篇文章。

二.K210色块识别

1.必要知识

K210的使用和Openmv不尽相同,使用的库函数都是一致的,由于Sipeed官网给出的例程实在是太少,于是就在Openmv的官网上查找资料,.

网站是这两个:序言 · OpenMV中文入门教程OpenMV Cam快速参考 — MicroPython 1.9.2 文档 (singtown.com)

由于之前有一定的Python的基础知识,看起来还是比较轻松的,如果没有Python的基础知识建议去这个网站大致看一看,比如for循环的语法,if的语法,while循环的语法,以及列表,元组,以及函数的定义和引用,这些和C有区别的东西看一看,敲一敲代码,大致也能记住,有C的基础的话看这些东西还是很快的。

2.色块识别

import sensor
import image
import lcd
import time

from machine import UART #串口库函数
from fpioa_manager import fm # GPIO重定向函数

sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QQQVGA)
sensor.skip_frames()

fm.register(7, fm.fpioa.UART1_TX, force=True)
fm.register(6, fm.fpioa.UART1_RX, force=True)
uart_A = UART(UART.UART1, 115200, 8, 0, 1)

def sending_data(x,y,z):
    FH = bytearray([0x2C,0x12,x,y,z,0x5B])
    uart_A.write(FH);

Threshold = (20, 66)
roi1 = (0,10,80,10)
cy = cz =24
while 1:
    img = sensor.snapshot()
    blobs = img.find_blobs([Threshold],roi = roi1,merge=True)
    if blobs:
        for blob in blobs:
            img.draw_rectangle(blob[0:4])
            img.draw_cross(blob[5], blob[6])
            distance = blob.cx()
            sending_data(distance,cy,cz)
    else:
        distance = 0

下面开始进行色块识别的内容:

我先贴出代码,一行一行的解释代码的作用(代码不多,非常简单,只有发送的部分,接收的部分之后再添加)

首先是sensor部分:

第一个是初始化感光元件的代码,这部分是默认的,只要你使用摄像头,这一行都要添加。

然后设置图像是灰度图像还是彩色图像,我在这里使用灰度图,基本上很多识别任务(数字识别、小球位置的识别等)都可以用灰度图,并且数据的处理量还小,能加快运行的速度,如果之后再加入一些识别的任务的话,能够提高一些帧数。

第三个是设置图像的大小,这是从官网截下来的设置图像大小的方法:

  • sensor.set_framesize() 设置图像的大小
  • sensor.QQCIF: 88×72
  • sensor.QCIF: 176×144
  • sensor.CIF: 352×288
  • sensor.QQSIF: 88×60
  • sensor.QSIF: 176×120
  • sensor.SIF: 352×240
  • sensor.QQQQVGA: 40×30
  • sensor.QQQVGA: 80×60
  • sensor.QQVGA: 160×120
  • sensor.QVGA: 320×240
  • sensor.VGA: 640×480
  • sensor.HQQQVGA: 80×40
  • sensor.HQQVGA: 160×80
  • sensor.HQVGA: 240×160
  • sensor.B64X32: 64×32 (用于帧差异 image.find_displacement())
  • sensor.B64X64: 64×64 用于帧差异 image.find_displacement())
  • sensor.B128X64: 128×64 (用于帧差异 image.find_displacement())
  • sensor.B128X128: 128×128 (用于帧差异 image.find_displacement())
  • sensor.LCD: 128×160 (用于LCD扩展板)
  • sensor.QQVGA2: 128×160 (用于LCD扩展板)
  • sensor.WVGA: 720×480 (用于 MT9V034)
  • sensor.WVGA2:752×480 (用于 MT9V034)
  • sensor.SVGA: 800×600 (仅用于 OV5640 感光元件)
  • sensor.XGA: 1024×768 (仅用于 OV5640 感光元件)
  • sensor.SXGA: 1280×1024 (仅用于 OV5640 感光元件)
  • sensor.UXGA: 1600×1200 (仅用于 OV5640 感光元件)
  • sensor.HD: 1280×720 (仅用于 OV5640 感光元件)
  • sensor.FHD: 1920×1080 (仅用于 OV5640 感光元件)
  • sensor.QHD: 2560×1440 (仅用于 OV5640 感光元件)
  • sensor.QXGA: 2048×1536 (仅用于 OV5640 感光元件)
  • sensor.WQXGA: 2560×1600 (仅用于 OV5640 感光元件)
  • sensor.WQXGA2: 2592×1944 (仅用于 OV5640 感光元件
  • 我使用的是sensor.QQQVGA,也就是80×60的分辨率,识别的效果还可以,根据自己的实际需求进行添加即可。

    最后一个跳过最开始的一些不稳定的图像。

    然后配置串口,使用7,6引脚作为数据的TX,RX端

    再定义一个函数,使用bytearray函数封装一个数组,作为发送给单片机的数据包

    使用UART_A.write(FH)发送数据包即可

    之后设置阈值(thresholds),至于如何设置阈值,可以看这个视频OpenMV巡线小车 | 星瞳科技

    感兴趣区的设置根据的自己的需求和实际的情况(也就是你摄像头摆放的位置,其实也可以用后期的调参来调整,直接使用和我一样的也可以)

    cx,cz预留一些位置用来做之后其他识别任务的传输,不影响目前的任务。

    在While循环里

    第一行是拍摄一张照片,获得一个image的对象,至于这个对象里面有什么统计信息,可以在

    OpenMV Cam快速参考 — MicroPython 1.9.2 文档 (singtown.com)

    这个网站的搜索栏里输入image就可以查找

    下一个是image.fin_blobs,也就是寻找色块的函数,这个函数的输入值也可以在上面那个网站里找到,我就不进行赘述了。

    注意一定要用if判断blob对象是否为None,否则一但识别不到色块,程序就会报错。

    识别到色块后用其中心的x坐标,也就是blob.cx()来作为输入量,传入数据包中发送给单片机。

    3.单片机的接收代码

    		if(UartHandle->Instance==USART2)
    		{
    				HAL_UART_Receive_IT(&huart2,&com_data,1);
    				if(RxState==0&&com_data==0x2C)  					//0x2c帧头
    				{
    					
    					RxState=1;
    					RxBuffer1[RxCounter1++]=com_data;
    				}
    		
    				else if(RxState==1&&com_data==0x12)  			//0x12帧头
    				{
    					RxState=2;
    					RxBuffer1[RxCounter1++]=com_data;
    				}
    		
    				else if(RxState==2)
    				{
    					RxBuffer1[RxCounter1++]=com_data;
     
    					if(RxCounter1==6 && com_data == 0x5B)   //RxBuffer1接受满了,接收数据结束
    					{
    						
    						cx=RxBuffer1[RxCounter1-4];
    						cy=RxBuffer1[RxCounter1-3];
    						cz=RxBuffer1[RxCounter1-2];
    						RxCounter1 = 0;
    						RxState = 0;	
    					}
    					else if(RxCounter1 > 6)            			//接收异常
    					{
    						RxState = 0;
    						RxCounter1=0;
    						for(i=0;i<6;i++)
    						{
    								RxBuffer1[i]=0x00;      					//将存放数据数组清零
    						}
    					
    					}
    				}
    				else   																		//接收异常
    				{
    						RxState = 0;
    						RxCounter1=0;
    						for(i=0;i<6;i++)
    						{
    								RxBuffer1[i]=0x00;      					//将存放数据数组清零
    						}
    				}
    		}
    		HAL_UART_Receive_IT(&huart2, (uint8_t *)RxBuffer, 1););

    我使用的是串口2,这部分代码是放在串口中断的回调函数里的,最后接受完之后注意要再开启接收,在main函数的while循环前也需要添加一样的代码来开启中断接收,cx是K210识别色块后发送回的色块的中心X坐标,如果要在其他.c文件里调用cx,在头文件里对cx进行一个extern的声明,然后在.c文件中进行定义,再在要使用cx的头文件里包含就可以了。

    三.通过蓝牙连接在电脑上实现PID的调参

    至于如何使用蓝牙在电脑上进行PID的调参,可以看我的另一篇有关平衡车的文章,里面写的很详细。

    到这里就基本结束了,至于数据包的解析,无非就是每接收1字节的数据进行一次中断,然后判断数据的帧头,再将有效的数据放入一个接收数组里,通过帧尾或者提前设定好的数据长度就可以接收了,还是非常简单的,就不进行赘述了(如果想要发送多于一个字节的数据,可以用多个一个字节的数据进行组合,取数据的高位,地位,然后进行组合就可以得到想要的数据了)

    效果视频我之后录制并发送到B站。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用STM32和K210进行PID巡线,通过蓝牙模块与电脑通信进行P、I、D参数调节

    发表评论