当前位置:   article > 正文

视觉巡线小车——STM32+OpenMV(三)_openmv巡线 线性回归

openmv巡线 线性回归

目录

前言

一、OpenMV代码

二、STM32端接收数据

1.配置串口

2.接收数据并解析

总结



前言

         通过视觉巡线小车——STM32+OpenMV(二),已基本实现了减速电机的速度闭环控制。要使小车能够自主巡线,除了能够精准的控制速度之外,还需要得到小车偏离黑线的差值——即位置偏差。本文将通过OpenMV得到该偏差。

        建议参考内容:

        OpenMV巡线小车 | 星瞳科技

        项目实例 · OpenMV中文入门教程

 系列文章请查看:视觉巡线小车——STM32+OpenMV系列文章 


一、OpenMV代码

        1、初始化外设,如串口等;

        2、运行主要代码,拍照,图像二值化处理,线性回归处理,得到黑线与OpenMV中心线之间的像素点偏差以及偏离角度。

        线性回归算法的原理是寻找一条最佳的直线来拟合数据点集。在视 觉巡线中,这些数据点就是二值化图像中代表线条的像素点。算法会计算这些像素点 的平均值、方差等统计量,并通过最小二乘法等来找到一条最佳的直线。

        3、将得到数据打包,并发送给STM32。

  1. THRESHOLD = (0, 23, -128, 127, -128, 127) # Grayscale threshold for dark things...
  2. import sensor, image, time
  3. from pyb import LED
  4. from machine import UART
  5. import struct
  6. sensor.reset()
  7. sensor.set_vflip(False) # 设置OpenMV图像“水平方向进行翻转”
  8. sensor.set_hmirror(False) # 设置OpenMV图像“竖直方向进行翻转”
  9. sensor.set_pixformat(sensor.RGB565)
  10. sensor.set_framesize(sensor.QQQVGA) # 80x60 (4,800 pixels) - O(N^2) max = 2,3040,000.
  11. # 线性回归算法的运算量大,越小的分辨率识别的效果越好,运算速度越快
  12. #sensor.set_windowing([0,20,80,40])
  13. sensor.skip_frames(time = 2000) # WARNING: If you use QQVGA it may take seconds
  14. clock = time.clock() # to process a frame sometimes.
  15. myuart = UART(1, 115200)
  16. # UART(1)是P0-RX P1-TX
  17. myuart.init(115200, bits=8, parity=None, stop=1) #8位数据位,无校验位,1位停止位
  18. def send_data_packet(x, y):
  19. temp = struct.pack(">bbii", #格式为小端模式俩个字符俩个整型
  20. 0xAA, #帧头1
  21. 0xBB, #帧头2
  22. int(x), # up sample by 4 #数据1
  23. int(y)) # up sample by 4 #数据2
  24. myuart.write(temp)
  25. #串口发送
  26. while(True):
  27. clock.tick()
  28. img = sensor.snapshot().binary([THRESHOLD])
  29. ''' 截取一张图片,进行 “阈值分割”
  30. 阈值分割函数image.binary()对图像进行二值化(binary:二元的;由两部分组成的)
  31. 得到的效果是:将阈值颜色变成白色,非阈值颜色变成黑色'''
  32. line = img.get_regression([(100,100)], robust = True)#调用线性回归函数
  33. # 对所有的阈值像素进行线性回归
  34. # 线性回归的效果就是将我们视野中“二值化”分割后的图像回归成一条直线
  35. if (line):
  36. rho_err = abs(line.rho())-img.width()/2
  37. # 计算我们的直线相对于中央位置偏移的距离(偏移的像素)
  38. # abs()函数:返回数字的绝对值 line.rho():返回霍夫变换后的直线p值。
  39. if line.theta()>90:
  40. theta_err = line.theta()-180
  41. else:
  42. theta_err = line.theta()
  43. # 进行坐标的变换:y轴方向为0°,x轴正方向为90°,x轴负方向为-90°
  44. img.draw_line(line.line(), color = 127)
  45. print(rho_err,line.magnitude(),theta_err)
  46. #line.magnitude()返回一个表示“线性回归效果”的值,这个值越大,线性回归效果越好;
  47. # 如果越接近于0,说明我们的线性回归效果越接近于一个圆,效果越差
  48. if line.magnitude()>8:
  49. send_data_packet(rho_err,theta_err)
  50. LED(1).off()
  51. else:
  52. LED(1).on()
  53. LED(2).off()
  54. else:
  55. LED(2).on()
  56. pass
  57. #print(clock.fps())

处理前后结果对比:

二、STM32端接收数据

1.配置串口

         由于OpenMV与STM32之间采用串口通讯,所以同样需要在CubeMX进行配置:

 同理也需要开启中断,这里不再赘述,参考上一篇文章。

2.接收数据并解析

        需要加入以下代码,进行初始化:

  1. //全局变量
  2. unsigned char OpenMV_Buf;
  3. int theta_org,rho_org;
  4. //初始化处加入
  5. HAL_UART_Receive_IT(&huart2,&OpenMV_Buf,1);

        在串口2中断回调函数中处理如下:

  1. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  2. {
  3. if(huart->Instance == USART2 )
  4. {
  5. // printf("OK\n");
  6. Rec_proce(OpenMV_Buf);
  7. HAL_UART_Receive_IT(&huart2,&OpenMV_Buf,1);
  8. }
  9. }
  10. void Rec_proce(u8 data)
  11. {
  12. static u8 RxBuffer[10];
  13. static u8 data_cnt = 0;
  14. static u8 state = 0;
  15. if(state==0&&data==0xAA)
  16. {
  17. state=1;
  18. }
  19. else if(state==1&&data==0xBB)
  20. {
  21. state=2;
  22. data_cnt = 0;
  23. }
  24. else if(state==2)
  25. {
  26. RxBuffer[data_cnt++]=data;
  27. if(data_cnt>=8)
  28. {
  29. state = 0;
  30. rho_org = (int)((RxBuffer[0]<<24) | (RxBuffer[1]<<16) | (RxBuffer[2]<<8) | (RxBuffer[3]));
  31. theta_org = (int)((RxBuffer[4]<<24) | (RxBuffer[5]<<16) | (RxBuffer[6]<<8) | (RxBuffer[7]));
  32. printf("%d,%d\n",rho_org,theta_org);
  33. // for(int i=0;i<8;i++) printf("%d",RxBuffer[i]);
  34. // printf("\n\n\n\n");
  35. }
  36. }
  37. else
  38. state = 0;
  39. }

         如果要使用printf进行打印输出,则需要加入以下代码,这里以串口3为例,如下:

  1. #include <stdio.h>
  2. int fputc(int ch,FILE *f)
  3. {
  4. while((USART3->SR & 0x40) == 0);
  5. USART3->DR = (uint8_t)ch;
  6. return ch;
  7. }

总结

通过本文,使用OpenMV得到中心线偏离黑线的像素点偏差和角度偏差,再将数据打包通过串口发送给STM32,最后在STM32上将数据解析出来,以便后续控制运用。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号