RoboGame参赛总结-4

RoboGame参赛总结-4

树莓派和STM32的串口搭建

本次使用的是树莓派4B,获取物块颜色后通过串口返回给STM32用于决策,树莓派4B的RXD和TXD的默认映射是ttyS0,一般认为这并不适合用于串口传输,需要改为ttyAMA0映射来形成稳定的传输路径。在尝试多次后,发现搞不定(
其实有一个更好的办法,事实上树莓派的USB接口可以直接作为USART的传输接口,使用一条microUSB的充电线把两个板子连接,就可以实现传输。

ser = serial.Serial("/dev/ttyUSB0", 115200)

但需要注意的是,USB的端口映射是动态的,每次连接的话需要确认USB口的Index值,可以通过指令确认

ls -l /sys/class/tty

还有一个要注意的,如果STM32连接了大量器件的话,本身STM32的电流就将达到2A以上,这时候STM32不能通过USB供电,需要外接其他的电源。否则树莓派将会罢工。
树莓派上的主函数:

import visual_capture
import cv2 as cv
import time
import numpy as np
import serial

cap = cv.VideoCapture(0)
ser = serial.Serial("/dev/ttyUSB0", 115200)
recv = ''
while True:
    success, image = cap.read()
    count = ser.inWaiting()
    if success is False:
        break
    # 参数换成src# 获取测试图像 可能需要调整缩放
    ObjectBuf = visual_capture.visual_object_run(image)
    # LineBuf = visual_capture.visual_line_run(image)
    # cv.imshow("capture", image)
    if count != 0:
        # read data
        recv = ser.read(count)
        recv = recv.decode()
        print(recv)
    # clear buffer
    ser.flushInput()
    if recv.find('obj') != -1:
        if ObjectBuf['object_amount'] is 0:
            ser.write(b'n\r\n')
        else:
            str = ObjectBuf['color']+'\r\n'
            # ser.write(b'color\r\n')
            ser.write(str.encode('gbk'))
            print(str)
    time.sleep(0.04)
    recv = ''
    c = cv.waitKey(40)
    # cv.imshow('image', image)
    if c == 27:  # 判断escape
        break
cv.waitKey(0)
cv.destroyAllWindows()

值得注意的是,这种通信方式中,树莓派和STM32的编码格式存在区别,即每个语句需要添加’\r\n’,并执行编码命令

ser.write(str.encode('gbk'))

这样STM32才能正确获取树莓派回传的字符。

视觉识别

这个比赛的要求很简单,只需要读出三种颜色就行,先按照HSV的相关表格创建红黄绿三种颜色的取值范围。

color_data = {'greenUp': np.array([77, 255, 255]), 'greenDown': np.array([35, 43, 46]),
                  'yellowUp': np.array([34, 255, 255]), 'yellowDown': np.array([26, 43, 36]),
                  'redUp1': np.array([10, 255, 255]), 'redDown1': np.array([0, 43, 36]),
                  'redUp2': np.array([180, 255, 255]), 'redDown2': np.array([156, 43, 36])}
deal_image = visual_image_scale(image)[0]  # 缩放
deal_image = cv.GaussianBlur(deal_image, (3, 3), 2)
hsv_image = cv.cvtColor(deal_image, cv.COLOR_BGR2HSV)
# 创建颜色对应的掩膜

这里先对图像做了一个小的高斯滤波,除去部分噪声,之后按照创建好的list创建三张掩膜覆盖后的图像。

red_mask1 = cv.inRange(hsv_image, color_data['redDown1'], color_data['redUp1'])
red_mask2 = cv.inRange(hsv_image, color_data['redDown2'], color_data['redUp2'])
red_mask = cv.bitwise_or(red_mask1, red_mask2)
yellow_mask = cv.inRange(hsv_image, color_data['yellowDown'], color_data['yellowUp'])
green_mask = cv.inRange(hsv_image, color_data['greenDown'], color_data['greenUp'])

之后进行图像处理,获取二值图进行开操作,除去小的噪声点

gray = cv.cvtColor(deal_image, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
    # 形态学处理
kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
binary = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)  # 开操作

直接使用OTSU快速二值化,获取较大的图像块,并进行反二值化。
完成之后获取边缘图像边缘:

binary,  contours, hireachy = cv.findContours(binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)

得到相关数据后,可以进一步对图像的特征进行筛选,并在图像上进行标注处理

    for index, contour in enumerate(contours):
        area = cv.contourArea(contour)
        # 面积
        rect_x, rect_y, rect_width, rect_height = cv.boundingRect(contour)
        # 外接矩形特征
        rate = max(rect_width, rect_height) / min(rect_width, rect_height)
        # print(str(color) + " rectangle rate-%s: %s" % (index, rate))
        mm = cv.moments(contour)
        # 重心参数
        # print(type(mm))
        if area == 0:
            continue
        cx = int(mm['m10'] / mm['m00'])
        cy = int(mm['m01'] / mm['m00'])
        # 多边形描绘
        approxCurve = cv.approxPolyDP(contour, 4, True)
        # print(str(color) + " approxCurve-%s:" % index)
        # print(approxCurve.shape)
        if approxCurve.shape[0] >= 4 and (area < (height*width-4000) and area > height*width/5):
            # 绘制红色外接矩形及其矩心
            cv.circle(deal_image, (np.int(cx), np.int(cy)), 2, (0, 0, 255), -1)
            cv.rectangle(deal_image, (rect_x, rect_y), (rect_x + rect_width, rect_y + rect_height), (0, 0, 255), 2)
            # 选取面积较大的矩形 绘制绿色边缘
            cv.drawContours(deal_image, contours, index, (0, 255, 0), 2)
            core_location.append((cx, cy))
            object_counter = object_counter + 1
            # print(str(color) + " contour-%s: area: %s" % (index, area))
        pass
#     cv.imshow(str(color) + " measure_contours", deal_image)

将数据整理后回传

 objectinf_dict = {'color': color, 'core_location': core_location, 'object_amount': object_counter}

效果如图:
在这里插入图片描述

STM32串口接收

这个一般的教程都有,很简单,不再赘述,但要回传注意速度不能过快,否则会出问题。

if(counter == 10){
		counter = 0;
		Usart_SendString(USART1, commond);
		delay_ms(1);
		if(USART_RX_STA&0x8000){
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			ObjectSearchNode->color = USART_RX_BUF[len-1]; //获取最新的数据
			if(ObjectSearchNode->vedio_en == 0) ObjectSearchNode->color = 0;
			if(ObjectSearchNode->color == 'r' && red_trigger){
				MissionCarryNode->red_index = ObjectSearchNode->line_index +1;
				red_trigger = 0;
			}
			USART_RX_STA = 0;
		}
	}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值