如果有嵌入式企业需要招聘校园大使,湖南区域的日常实习,任何区域的暑假Linux驱动实习岗位,可C站直接私聊,或者邮件:zhangyixu02@gmail.com,此消息至2025年1月1日前均有效

前言

(1)废话少说,很多人可能无法访问GitHub,所以我直接贴出可能要用的代码。此博客还会进行更新,先贴教程和代码
(2)
<1>视频教程: https://singtown.com/learn/49603/
<2>OpenMV追云台官方Github链接 :https://github.com/SingTown/OpenMV-Pan-Tilt/tree/master/pan-tilt/src
(3)有些人肯定说红点太小了,OpenMV不行精度不够,看这个C站上做出来的阈值代码:https://blog.csdn.net/weixin_52385589/article/details/126334744
(4)赛事方肯定不可能直接让你上现成的玩意,不然比赛的意义在哪里?我看了一下网上的一些讨论。肯定是要用摄像头的,K210好像有官方库,K210的同学可以了解一下。
(5)OpenMV的话需要多训练,建议最好做灯光补偿,毕竟OpenMV对灯光要求很高,环境光线一点要稳定!!!
注意:有网友反馈,官方说不能使用灯光补偿。我没得到相关信息,请各位确认之后再决定要不要使用灯光补偿。
(6)各位,有问题尽量C站私信。因为评论太多了,我容易漏掉。(虽然写评论区可以给我加热度,哭)
(7)这篇博客是会根据情况实时更新的,所以请各位注意刷新。
(8)再次强调,提供的都是伪代码!!!肯定会报错!!!要自己调整!!!我只提供思路,饭都端上来了,还不能吃吗?!
(9)更新日记:
<1>2023年8月2日,上午9点。OpenMV官方的追云台代码,以及相关解读。
<2>2023年8月2日,上午10点。增加C站另一位大佬的调试结果代码。
<3>2023年8月2日,下午2点。更改错别字,增加基础题思路。
<4>2023年8月2日,下午2点10分。增加网友的一些提问。
<5>2023年8月2日,下午2点40分。更改了前言部分,希望各位问问题私信我,因为写在评论区有时候会被刷新掉。
<6>2023年8月2日,下午2点50分。更新了基础题的思路,第四问还有待商榷。
<7>2023年8月2日,下午3点。更新了网友的一些问题
<8>2023年8月2日,下午3点40分。关于OpenMV的鱼眼畸变可能带来的问题,增加了软硬件解决方案。
<9>2023年8月2日,下午4点35分。关于代码报错问题回复,器件选择问题。
<10>2023年8月2日,下午5点30分。更新关于购买推荐的OpenMV云台可能导致的问题,以及据说可行的现成方案。
<11>2023年8月2日,下午6点。更新鱼眼畸变代码报错问题,基础题的第一问和第二问代码给出来了
<12>2023年8月2日,下午6点20分。更新了关于博客视频的资料在哪里,关于代码怎么获取。
<13>2023年8月2日,下午6点40分。关于K210,OpenART mini,OpenMV代码问题回答。
<14>2023年8月2日,下午7点30分。回答网友,舵机抽搐问题,OpenMV与主控通讯,第一问和第二问舵机控制不稳定。
<15>2023年8月2日,下午9点20分。更新推荐舵机,数字舵机比模拟舵机精度更高。
<16>2023年8月3日,12点睡觉前最后一次更新。关于激光和OpenMV安装位置。
<17>2023年8月3日,9点50分。更新了OpenART mini移植到OpenMV的方案,将网友回答专门组成了一篇博客。
<18>2023年8月3日,10点30分。更新发挥题目思路。
<19>2023年8月3日,11点30分。将目前反馈可行方案放在了最醒目的地方。
<20>2023年8月4日,9点20分。将基础题第三问进行了微调。将基础题和发挥题分离。发挥题还在补充思路,基础题也会在中午前补充完思路。请不要着急。
<21>2023年8月4日,10点30分。基础题的所有测试思路都给出来了,伪代码也给了,硬件测试思路也给了,还做不出来,真的就一点救都没有了。

网上所宣传的现成可行方案

OpenART mini的同学看这个

(1)我看网上有人说OpenART mini有一个现成的方案。如果会OpenART mini的同学,可以尝试。以下是这个资料
(2)百度网盘资料:
OpenART min模块资料链接:https://pan.baidu.com/s/1yoCNXzci_dfHzW33emxdLA
提取码:mxx8

在这里插入图片描述

(3)关于云台控制:
<1>云台由两个舵机组成,下面的舵机控制偏航角(左右)旋转,上面的舵机控制俯仰角(上下)旋转。
<2>如果在云台上面安装一个激光发射装置,当我们控制单个舵机旋转时,观察激光路径发现是一条直线,并且云台的两个舵机路径分别是一个水平和一个垂直的直线,如果我们同时控制两个舵机旋转的舵机就可以实现在一个面的任意位置激光投影。
<3>若此时我们需要控制舵机按照设定的固定路径移动,当路径为线段时,仅需要知道线段的起点坐标和终点坐标即可(坐标对应舵机的高电平时间,也就是占空比),如果直接将起点和终点输出到云台舵机,会发现虽然到达了起点和终点,但路径并非直线路径,这是由于X轴和Y轴移动距离不一致而产生的,因此需要将这条线段细分,比如通过起点坐标和终点坐标将线段细分为1000份,每次仅移动一份的距离,此时就会发现激光的路径沿着线段逐渐移动了。
<4>如果需要移动的路径为一个闭合矩形,我们仅需得到矩形的四个角的坐标,按照上面线段的分段移动的方式,分别将四条边细分后再控制舵机逐渐移动,即可实现看起来较为丝滑的闭合矩形路径。
<5>在编写控制程序时,如果采用这样分段移动的方式,那么我们可以将程序段放置在周期中断内执行,此时就可以确立单次移动的时间,从而控制整体的移动速度。移动速度的控制是必须的,不管是路径稳定还是点位追踪都需要涉及到移动速度的精准控制。
(4)E题中所涉及到的主控型号赛题没有任何限制,可以使用智能车竞赛中的核心板(例如RT1064、TC264、CH32V307、STC),其中RT1064主板有三个舵机接口,可以比较方便控制云台,激光也没有限制,只要求了光斑大小小于等于1厘米即可。
(4)关于这个方案的相关影像资料:

1

2


5


4

6

OpenMV的同学看这个

点开这个链接:2023年电赛—运动目标控制与自动追踪系统(E题)OpenART mini的代码移植到OpenMV

硬件注意事项

接线问题

(1)我们这里是使用的OpenMV的P8和P7引脚。所以建议引脚如下图引出。
(2)舵机一般是5V供电,所以注意VCC是供5V的电压。而右边那两个GND和VCC是连接OpenMV的。如果右边的VCC是连接OpenMV的VIN引脚,就可以供5V电。如果是连接OpenMV的3.3V引脚,iu只能供3.3V电压。否则OpenMV会被烧掉!
(3)舵机的VCC要直接连接电池,因为如果通过OpenMV连接,OpenMV的输出电流太小,带不动舵机!

在这里插入图片描述

云台购买推荐

(1)一开始我推荐使用这一款。后面根据别人反馈,精度不够。所以我还是推荐我之前吐槽的那个奇奇怪怪的舵机啊。(被打脸了,哈哈哈)

在这里插入图片描述

(2)推荐这一款,虽然不需要这么大的扭矩,但是他是数字舵机,精度更高。

在这里插入图片描述

OpenMV鱼眼畸变

(1)我刚刚上机测试了一下,突然发现OpenMV存在鱼眼畸变。
(2)鱼眼畸变就是,摄像出来的图片就像鱼的眼睛看到的图片一样,不是平的。
(3)这个会不会有影响不清楚。
(4)从硬件上处理办法就是换一个无畸变镜头,官方链接 :
https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w5003-18207055866.1.6b0b1dc1nPB6IZ&id=601956249175&scene=taobao_shop
(5)来不及的话,可以使用软件方法。但是我测试了,好像没有反应。
<1>我们购买的OpenMV的默认镜头是带鱼眼效果的,所以需要进行畸变矫正(注意:此处运算量大,不建议长时间使用OpenMV不然会发烫很严重
<2>因为我们这里没有指定是传入的zoom,x_corr,y_corr的值,所以按照顺序,传入的1.8是给strength。我们可以调节这个值,来查看即便矫正的效果,建议从1.8开始尝试。
<3>zoom就是进行图像缩放,比如10X10的图像,为0.5,就算5X5的图像。建议为默认值,只需要调节strength就行了。
<4>后面这个x和y是什么,官方文档没有解释。
(6)真的太多人不喜欢认真看博客了,说了是伪代码,要自己调整。还要问!我这里还是给这真正0~基础的人,贴出来,别再问了!

import sensor, image
img = sensor.snapshot() # 截取一张图片
img.lens_corr(1.8)  #去除鱼眼畸变

在这里插入图片描述

出现Frame capture has timed out. 帧捕获超时了

(1)如果是我贴出来的代码,出现这个bug。你重新开机启动应该就可以了。
(2)如果还不可以,就说明你OpenMV坏了。要快点换一个。

在这里插入图片描述

基础题思路

(1)以下均为个人思路,仅供参考。
(2)个人认为基础题不需要使用PID,只需要一个OpenMV,两个舵机,一个云台就可以了。
(3)OpenMV控制舵机的教程:OpenMV输出PWM,实现对舵机控制
(4)根据网友反馈,本题不需要用PID!常见的数字舵机就行了!!!别跟我扯算法!!!

第一问—复位

(1)这个比较简单,我感觉只需要写入一个固定值,给舵机一个固定的PWM就可以了。
(2)关于按键问题,你们可以使用下面的函数实现。
<1>这里的pyb.Pin第一个参数是你用于读取按键值的。
<2>第二个参数可以获得引脚上的按键值。
<3>按键电路如下,并联上一个104的电容,是用于硬件消抖。

import pyb
p = pyb.Pin("P0", pyb.Pin.IN)
key_value = p.value() # Returns 0 or 1.

在这里插入图片描述

第二问—沿A4纸移动

(1)和第一问一样,我认为写一个死的程序就行了,因为他的屏幕给定了0.5m*0.5m。
(2)有一些人问第一问和第二问切换问题

import pyb, time
p = pyb.Pin("P0", pyb.Pin.IN)
clock = time.clock() # 追踪帧率,影响不大
while True:
	key_value = p.value() # Returns 0 or 1.
    if key_value == 1:
        key_time_first  = clock.tick() #开始计时
        Task1 = 1
        while key_value == 1: #一直等待松手
            pass
    if key_value == 0:  #确认松手
        key_time_last = clock.avg()
        if(key_time_last-key_time_first> 2000) :  #如果按键按下时间超过2s
            # 进入任务2
            pass   # 这个是表示不进行任何操作!!!
        elif Task1 == 1 : #如果按键按下时间小于1s
            # 进入任务1
            pass

第三问—黑色边框检测

(1)时间太紧急了,我就讲一下思路。
<1>我们使用blobs = img.find_rects([red_threshold]),找到黑色边框。
<2>调用max_blob = find_max(blobs),找到最大的黑色边框。因为可能存在其他的干扰。
<3>找到边框之后,调用max_blob.x(),max_blob.y(),max_blob.w(),max_blob.h()分别获得识别到的边框左上角的x坐标,y坐标,宽度和长度。
<4>不明白的可以看下面这个图,假设0包含的地方是屏幕,11选中的是黑框内,我们最终返回的值如下图。
(2)有网友提供,说出现了NameError:name img isn’t defined的报错。是因为我只是截取了代码中的一部分。前面的没写,为了方便新手朋友使用,我还是加上。
(3)但是,请各位注意,摄像头的初始化

import sensor, image, time

sensor.reset() # 初始化摄像头传感器
sensor.set_pixformat(sensor.RGB565) # 使用 RGB565 彩图
sensor.set_framesize(sensor.QQVGA) # 使用 QQVGA 分辨率
sensor.skip_frames(10) #跳过几帧,让新的设置生效。
sensor.set_auto_whitebal(False) # 因为是颜色识别,所以需要把白平衡关闭
clock = time.clock() # 追踪帧率,影响不大
#__________________________________________________________________
#定义寻找最大色块的函数,因为图像中有多个色块,所以追踪最大的那个
def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob[2]*blob[3] > max_size:
            max_blob=blob
            max_size = blob[2]*blob[3]
    return max_blob
#__________________________________________________________________
while(True):
	clock.tick() # 跟踪快照()之间经过的毫秒数。
	img = sensor.snapshot() # 截取一张图片
	blobs =  img.find_rects(threshold = 10000) #识别矩形框
	max_blob = find_max(blobs)  #调用上面自定义函数,找到最大色块
	max_blob.x()  #返回识别区域左上角的x坐标
	max_blob.y()  #返回识别区域左上角的y坐标
	max_blob.w()  #返回识别区域的宽度
	max_blob.h()  #返回识别区域的长度

在这里插入图片描述

第四问—黑色边框检测

(1)这个和第三问舵机控制有区别,第三问是一个舵机一个舵机的控制。而这一题需要两个舵机同时控制。
(2)看2023年电赛—运动目标控制与自动追踪系统(E题)OpenART mini的代码移植到OpenMV这一篇博客

关于基础题的硬件调试思路

(1)需要准备的器材:示波器,信号发生器,万用表。
(2)很多人反馈数字舵机不行,我的方法不行。而也有一部分同学说我的方法是可行的。所以说我希望各位先测试一下,是不是自己硬件上出现的问题。

数字舵机,机械结构的检测方法

(1)我们先找到一个信号发生器,让信号发生器上产生一个PWM波形。然后通过调节信号发生器上的PWM,让云台沿着正方形框框移动。
(2)同时,我们观察是否能够很好的运行。如果可以,记录下来沿着正方形框框运动的四个点位PWM值。 如果不可以很好的运行,说明你的云台或者说舵机有问题,快点换!
(3)如果可以,我们开始测量舵机的最小分辨率。数字舵机是有一个最小分辨率的,比如说,你一个20ms周期的方波,高电平是500us和高电平550us的情况可能是一样的!也就是说,你这一款舵机的分辨率达不到50us的精度!
(4)测试舵机分辨率,我建议从500us开始测试。然后改变了高电平持续时间,一直调整到发现舵机有移动了!那么就说明找到了舵机分辨率。找到分辨率之后,记录下来,之后有用。

PWM输出的稳定性测量

(1)你将上面记录下来的PWM值,编程写出来。然后拿示波器测试,看看能否产生指定的PWM值。
(2)如果示波器上能够输出你记录的四个点位,否则说明你程序有问题或者是主控坏了。那么把结构拼装好。然后开机测试,注意,这里不需要进行图像识别!!!只是单纯的四个PWM点位输出!!!
(3)如果云台能够按照指定的四个点位运行,那么你第二问就做出来了 。如果没有,说明你接线有问题!
(4)怎么知道哪里接线有问题呢?那万用表测试,开到蜂鸣器挡位,一点一点的测试主控和云台的接线,如果发现哪里蜂鸣器不叫,或者是叫的断断续续的,说明有可能接线不稳定!!!
(5)这个时候就要加上焊锡固定了。

如何找到PWM输出量和图像数据的关系

(1)找关系的事情,我建议OpenMV先和电脑连接上,使用print函数将矩形的四个点位数据打印到电脑终端。
(2)然后拿信号发生器输出PWM,看看舵机每运转动一个最小分辨率,像素点移动多少。找到像素点移动的值之后,记录像素点,和PWM高电平变化。进行建模分析,应该是线性关系。
(3)建模完成之后,将这个线性关系编程,然后第三问就做出来了。

关于第四问的细分路线

(1)这个时候,上面用信号发生器检测出来的舵机最小分辨率就有作用了。
(2)我们通过线性建模关系和最小分辨率,可以计算出,此次运动要进行多少次细分。也不一定要根据最小分辨率来啊!
(3)伪代码如下

//假设这是一个20ms的中断
void 20ms_interrupt()
{
	x_PWM_max = x_linearity(x_img); //通过你找到的线性关系,将像素点值转换成PWM值
	y_PWM_max = y_linearity(y_img); //通过你找到的线性关系,将像素点值转换成PWM值
	if(x_PWM_current < x_PWM_max ) //PWM限幅
	{
		x_PWM_current += x_PWM_interval; //每次增加最小分辨率个PWM值
		PWM_SET(x_PWM_current ); //调用PWM输出函数,将PWM值输出
	}
	if(y_PWM_current < y_PWM_max ) //PWM限幅
	{
		y_PWM_current += y_PWM_interval; //每次增加最小分辨率个PWM值
		PWM_SET(y_PWM_current ); //调用PWM输出函数,将PWM值输出
	}
}

发挥题思路链接

点开链接:2023年电赛—运动目标控制与自动追踪系统(E题)发挥题思路

网友提问 和 E题官方解释

问问题前先看这个!
点开这个链接:2023年电赛—运动目标控制与自动追踪系统(E题)关于网友的问题回复

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐