视觉巡线小车——STM32+OpenMV(三)

目录

前言

一、OpenMV代码

二、STM32端接收数据

1.配置串口

2.接收数据并解析

总结



前言

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

        建议参考内容:

        OpenMV巡线小车 | 星瞳科技

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

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


一、OpenMV代码

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

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

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

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

THRESHOLD = (0, 23, -128, 127, -128, 127) # Grayscale threshold for dark things...
import sensor, image, time
from pyb import LED
from machine import UART
import struct

sensor.reset()
sensor.set_vflip(False)   # 设置OpenMV图像“水平方向进行翻转”
sensor.set_hmirror(False) # 设置OpenMV图像“竖直方向进行翻转”

sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQQVGA) # 80x60 (4,800 pixels) - O(N^2) max = 2,3040,000.
 # 线性回归算法的运算量大,越小的分辨率识别的效果越好,运算速度越快

#sensor.set_windowing([0,20,80,40])
sensor.skip_frames(time = 2000)     # WARNING: If you use QQVGA it may take seconds
clock = time.clock()                # to process a frame sometimes.

myuart = UART(1, 115200)
# OpenMV RT 只有串口UART(1),对应P4-TX P5-RX; OpenMV4 H7 Plus, OpenMV4 H7, OpenMV3 M7 的UART(1)是P0-RX P1-TX
myuart.init(115200, bits=8, parity=None, stop=1)  #8位数据位,无校验位,1位停止位

def send_data_packet(x, y):
    temp = struct.pack(">bbii",                #格式为小端模式俩个字符俩个整型
                   0xAA,                       #帧头1
                   0xBB,                       #帧头2
                   int(x), # up sample by 4    #数据1
                   int(y)) # up sample by 4    #数据2
    myuart.write(temp)
                              #串口发送
while(True):
    clock.tick()
    img = sensor.snapshot().binary([THRESHOLD])
    ''' 截取一张图片,进行 “阈值分割”
    阈值分割函数image.binary()对图像进行二值化(binary:二元的;由两部分组成的)
    得到的效果是:将阈值颜色变成白色,非阈值颜色变成黑色'''
    line = img.get_regression([(100,100)], robust = True)#调用线性回归函数
     # 对所有的阈值像素进行线性回归
     # 线性回归的效果就是将我们视野中“二值化”分割后的图像回归成一条直线
    if (line):
        rho_err = abs(line.rho())-img.width()/2
        # 计算我们的直线相对于中央位置偏移的距离(偏移的像素)
        # abs()函数:返回数字的绝对值  line.rho():返回霍夫变换后的直线p值。
        if line.theta()>90:
            theta_err = line.theta()-180
        else:
            theta_err = line.theta()
        # 进行坐标的变换:y轴方向为0°,x轴正方向为90°,x轴负方向为-90°

        img.draw_line(line.line(), color = 127)

        print(rho_err,line.magnitude(),theta_err)
        #line.magnitude()返回一个表示“线性回归效果”的值,这个值越大,线性回归效果越好;
        # 如果越接近于0,说明我们的线性回归效果越接近于一个圆,效果越差
        if line.magnitude()>8:
            send_data_packet(rho_err,theta_err)
            LED(1).off()
        else:
            LED(1).on()
        LED(2).off()
    else:
        LED(2).on()
        pass
    #print(clock.fps())

处理前后结果对比:

二、STM32端接收数据

1.配置串口

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

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

2.接收数据并解析

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

//全局变量
unsigned char OpenMV_Buf;
int theta_org,rho_org;


//初始化处加入
HAL_UART_Receive_IT(&huart2,&OpenMV_Buf,1);

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

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART2 )
    {
//       printf("OK\n");
       Rec_proce(OpenMV_Buf);                 
       HAL_UART_Receive_IT(&huart2,&OpenMV_Buf,1); 
    }
}
void Rec_proce(u8 data)
{
    /* 局部静态变量:接收缓存 */
    static u8 RxBuffer[10];
    /* 数据长度 *//* 数据数组下标 */
    static u8  data_cnt = 0;
    /* 接收状态 */
    static u8 state = 0;
    /* 帧头1 */
    if(state==0&&data==0xAA)
    {
        state=1;
    }
    /* 帧头2 */
    else if(state==1&&data==0xBB)
    {
        state=2;
        data_cnt = 0;
    }
    /* 接收数据租 */
    else if(state==2)
    {
        RxBuffer[data_cnt++]=data;
        if(data_cnt>=8)
        {
            state = 0; 
            rho_org   = (int)((RxBuffer[0]<<24) | (RxBuffer[1]<<16) | (RxBuffer[2]<<8) | (RxBuffer[3]));  
            theta_org = (int)((RxBuffer[4]<<24) | (RxBuffer[5]<<16) | (RxBuffer[6]<<8) | (RxBuffer[7]));            
            printf("%d,%d\n",rho_org,theta_org);
//            for(int i=0;i<8;i++) printf("%d",RxBuffer[i]);
//            printf("\n\n\n\n");
        }
    }
    /* 若有错误重新等待接收帧头 */
    else
        state = 0;
}

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

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

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/843169.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【BUG】已解决:raise KeyError(key) from err KeyError: (‘name‘, ‘age‘)

已解决&#xff1a;raise KeyError(key) from err KeyError: (‘name‘, ‘age‘) 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xf…

第十课:telnet(远程登入)

如何远程管理网络设备&#xff1f; 只要保证PC和路由器的ip是互通的&#xff0c;那么PC就可以远程管理路由器&#xff08;用telnet技术管理&#xff09;。 我们搭建一个下面这样的简单的拓扑图进行介绍 首先我们点击云&#xff0c;把云打开&#xff0c;点击增加 我们绑定vmn…

idea如何让包结构分层

文章目录 前言1.选中前项目包结构2.取消后项目包结构3.情况二 前言 在大型项目中&#xff0c;代码的分层管理至关重要。IDEA编辑器提供了强大的package分层结构功能&#xff0c;帮助开发者更好地组织和管理代码。通过合理配置&#xff0c;我们可以清晰地看到各个package之间的…

【BUG】已解决:java.lang.reflect.InvocationTargetException

已解决&#xff1a;java.lang.reflect.InvocationTargetException 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发…

Mysql-索引结构

一.什么是索引&#xff1f; 索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引 二.无索引的情况 找到…

【效率提升】程序员常用Shell脚本

文章目录 常用Shell脚本一. 定期更新分区数据二、获取系统资源的使用情况 常用Shell脚本 一. 定期更新分区数据 在某些场景下&#xff0c;我们需要对N年前某一分区的数据进行删除&#xff0c;并添加今年该对应分区的数据&#xff0c;实现数据的流动式存储。 #!/bin/bash dt$…

NFT革命:数字资产的确权、营销与元宇宙的未来

目录 1、NFT&#xff1a;数字社会的数据确权制度 2、基于低成本及永久产权的文化发现 3、PFP&#xff1a;从“小图片”到“身份表达”&#xff0c;再到社区筛选 4、透明表达&#xff1a;NFT 在数字化营销中的商业价值 5、可编程性&#xff1a;赋予 NFT 无限可能的应用 5.…

微信被好友屏蔽朋友圈/拉黑/删除?教你几招悄悄验证

微信这一国民级的社交软件&#xff0c;基本上渗入了大家日常生活的方方面面&#xff0c;沟通、支付、购物、娱乐都可以在上面一站式解决。微信功能虽然很全面&#xff0c;但某些功能细节设计也会让人感到困惑&#xff0c;比如我们被朋友拉黑或者删除&#xff0c;微信是不会通知…

C程序优化与指针传址

最近在写程序时遇到了一些问题&#xff0c;记录一下&#xff1a; 开始程序使用全局变量&#xff0c;程序如下&#xff1a;程序的缺点是全局变量的泛滥。 笔者觉得有些不妥&#xff0c;于是将它修改成这样&#xff1a; 使用结构体进行封装&#xff0c;避免了全局变量&#xff0…

Gitee使用教程2-克隆仓库(下载项目)并推送更新项目

一、下载 Gitee 仓库 1、点击克隆-复制代码 2、打开Git Bash 并输入复制的代码 下载好后&#xff0c;找不到文件在哪的可以输入 pwd 找到仓库路径 二、推送更新 Gitee 项目 1、打开 Git Bash 用 cd 命令进入你的仓库&#xff08;我的仓库名为book&#xff09; 2、添加文件到 …

转移C盘中的conda环境(包括.condarc文件修改,environment.txt文件修改,conda报错)

conda环境一般是默认安装到C盘的&#xff0c;若建立多个虚拟环境&#xff0c;时间长了&#xff0c;容易让本不富裕的C盘更加雪上加霜&#xff0c;下面给出将conda环境从C盘转移到D盘的方法。 目录 电脑软硬件转移方法查看当前conda目录转移操作第一步&#xff1a;.condarc文件修…

C语言迷宫

目录 开头程序程序的流程图程序输入与输出的效果结尾 开头 大家好&#xff0c;我叫这是我58。今天&#xff0c;我要来看我用C语言编译出来的迷宫游戏。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <Windows.h> void printmaze(char s…

鸿蒙Navigation路由能力汇总

基本使用步骤&#xff1a; 1、新增配置文件router_map&#xff1a; 2、在moudle.json5中添加刚才新增的router_map配置&#xff1a; 3、使用方法&#xff1a; 属性汇总&#xff1a; https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-compone…

在RK3568上如何烧录MAC?

这里我们用RKDevInfoWriteTool 1.1.4版本 下载地址&#xff1a;https://pan.baidu.com/s/1Y5uNhkyn7D_CjdT98GrlWA?pwdhm30 提 取 码&#xff1a;hm30 烧录过程&#xff1a; 1. 解压RKDevInfoWriteTool_Setup_V1.4_210527.7z 进入解压目录&#xff0c;双击运行RKDevInfo…

H3CNE(计算机网络的概述)

1. 计算机网络的概述 1.1 计算机网络的三大基本功能 1. 资源共享 2. 分布式处理与负载均衡 3. 综合信息服务 1.2 计算机网络的三大基本类型 1.3 网络拓扑 定义&#xff1a; 网络设备连接排列的方式 网络拓扑的类型&#xff1a; 总线型拓扑&#xff1a; 所有的设备共享一…

Flutter 插件之 easy_refresh(下拉刷新、上拉加载)

今天给大家较少一下日常开发中最常见的一个功能,就是 下拉刷新、上拉加载,这个在我们使用分页功能是最常见的。 此前我我也写了一篇关于 下拉刷新、上拉加载。 Flutter 下拉刷新、上拉加载flutter_easyrefresh的使用https://blog.csdn.net/WangQingLei0307/article/details/…

阿里宜搭对接打通金蝶云星空搜索表单实例详情列表接口与仓库新增接口

阿里宜搭对接打通金蝶云星空搜索表单实例详情列表接口与仓库新增接口 来源系统:阿里宜搭 宜搭是阿里巴巴自研的低代码应用搭建平台&#xff0c;传统情况下需要2周才能搭建完成的应用&#xff0c;用宜搭2小时就可完成。宜搭于2019年3月上线&#xff0c;用户可以在可视化界面上以…

AI 模型本地推理 - YYPOLOE - Python - Windows - GPU - 吸烟检测(目标检测)- 有配套资源直接上手实现

Python 运行 - GPU 推理 - windows 环境准备python 代码 环境准备 FastDeploy预编译库下载 conda config --add channels conda-forge && conda install cudatoolkit11.2 cudnn8.2 pip install fastdeploy_gpu_python-0.0.0-cp38-cp38-win_amd64.whlpython 代码 impo…

WebGL-编译报错,如何定位sendfile报错位置

1&#xff09;WebGL-编译报错&#xff0c;如何定位sendfile报错位置 2&#xff09;设置DepthBufferBits和设置DepthStencilFormat的区别 3&#xff09;Unity打包exe后&#xff0c;游戏内拉不起Steam的内购 4&#xff09;使用了Play Asset Delivery提交版本被Google报错 这是第3…

【QT】label适应图片(QImage)大小;图片适应label大小

目录 0.简介 1.详细代码 1&#xff09;label适应img大小 2&#xff09;img适应label大小 0.简介 一个小demo &#xff0c;想在QLabel中放一张QImage的图片&#xff0c;我有一张图片叫【bird.jpg】&#xff0c;是提前放在资源文件中的&#xff0c;直接显示在label上后&#…