2023电赛E题大一菜鸡思路+代码

2023年的电赛结束了,我的大一生活也结束了
下面是我完成电赛E题的一些思路和我们组实际使用的代码
给给我大佬献丑了

  1. 根据题目给的任务要求我构建了这样的硬件环境
    1.C:直接做主控,当时说不让用步进电机索性直接拿它当主控了(后面确实后悔了)
    2.铝型材和角铁:分用了80和40的铝型材搭成的框架,稳的一批,甚至可以拿起来摇(狗头)
    3.屏幕:用的石灰板(楼下刚好在装修,而且好切)做的屏幕,在贴工图纸(够大)
    4.云台:最让我意难平的东西,选择的是SG90(实验室祖传的)精度和效果都让人很不满意
    主要就是这些了,其他外围电路没什么好说的没什么,基础部分的OpenMV用了配套的无畸变摄像头和OpenMV 舵机扩展板当时想着是把OpenMV 也放在一个单独的云台上矫正的(后面被要求禁止了),后面索性也没改,按键选择的是1*4的键盘(受限与OpenMV ),电源用的是220转12的学生电源,通过降压模块给舵机(这个确实是有必要的)和OpenMV 供电
  2. 基础部分1,2,3写死!!!没必要给自己找麻烦
  3. 基础4
import pyb
import sensor, image, time
from pid import PID
from servo import Servos
from machine import I2C, Pin
from pid import PID
from pyb import Servo
from pyb import Pin, ExtIntpan_servo=Servo(1)
tilt_servo=Servo(2)pan_pid = PID(p=0.04, i=0, imax=90) #脱机运行或者禁用图像传输,使用这个PID
tilt_pid = PID(p=0.04, i=0, imax=90) #脱机运行或者禁用图像传输,使用这个PID# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.RGB565) # 设置图像色彩格式为RGB565格式
sensor.set_framesize(sensor.QQVGA)  # 设置图像大小为160*120
sensor.set_auto_whitebal(True)      # 设置自动白平衡
sensor.set_brightness(3000)         # 设置亮度为3000
sensor.skip_frames(time = 0)       # 跳过帧clock = time.clock()
def function_c():					#对应按键选择基本部分4a = 80							#设置初始的x轴位置b = 80							#设置初始的y轴位置i = 0							#循环次数,判断是否跑了四个点w = 0h = 0global x, yclock.tick()  # 计时器开始img = sensor.snapshot()  # 获取图像print("RED", find_red(img))time.sleep_ms(500)  # 等待500毫秒# 在图像中寻找矩形for r in img.find_rects(threshold = 10000):# 判断矩形边长和颜色是否符合要求if r.w() > 20 and r.h() > 20:# 在屏幕上框出矩形img.draw_rectangle(r.rect(), color = (255, 0, 0), scale = 4)# 获取矩形角点位置corner = r.corners()# 在屏幕上圈出矩形角点img.draw_circle(corner[0][0], corner[0][1], 5, color = (0, 0, 255), thickness = 2, fill = False)img.draw_circle(corner[1][0], corner[1][1], 5, color = (0, 0, 255), thickness = 2, fill = False)img.draw_circle(corner[2][0], corner[2][1], 5, color = (0, 0, 255), thickness = 2, fill = False)img.draw_circle(corner[3][0], corner[3][1], 5, color = (0, 0, 255), thickness = 2, fill = False)# 打印四个角点坐标, 角点1的数组是corner[0], 坐标就是(corner[0][0],corner[0][1])# 角点检测输出的角点排序每次不一定一致,矩形左上的角点有可能是corner0,1,2,3其中一个# 记录四个角点的索引corners = [corner[0], corner[1], corner[2], corner[3]]curr_corner_index = 0  # 当前追踪的角点索引pan_servo.angle(80)  # 设置舵机水平角度tilt_servo.angle(77)  # 设置舵机垂直角度while True:jianpan()img.draw_rectangle(r.rect(), color = (255, 0, 0), scale = 4)img.draw_cross(corners[curr_corner_index][0], corners[curr_corner_index][1], color = (0, 0, 255), size = 1, thickness = 1)clock.tick()  # 计时器开始img = sensor.snapshot()  # 获取图像print("RED", find_red(img))time.sleep_ms(100)  # 等待pan_error = -corners[curr_corner_index][0] + x  # 计算水平方向的误差tilt_error = -corners[curr_corner_index][1] + y  # 计算垂直方向的误差print("error:", pan_error, tilt_error)pan_output = pan_pid.get_pid(pan_error,1)  # 使用PID控制器计算水平方向的输出值tilt_output = tilt_pid.get_pid(tilt_error, 1)/1  # 使用PID控制器计算垂直方向的输出值print("output", pan_output, tilt_output)a = a - pan_output # 调整水平舵机位置b = b + tilt_output  # 调整垂直舵机位置servo.position(1, a,300)  # 应用水平方向的输出值到舵机位置servo.position(0, b,300)  # 应用垂直方向的输出值到舵机位置print("angle", a, b)time.sleep_ms(150)  # 等待img = sensor.snapshot()  # 获取图像print("RED", find_red(img))time.sleep_ms(100)  # 等待500毫秒print(curr_corner_index,i)print("Laser Coordinate (a,b)", corners[curr_corner_index][0], corners[curr_corner_index][1])  # 打印当前角点的坐标# 判断pan_error和tilt_error的值是否小于5,如果小于5,认为角点已经找到,跳出循环if abs(pan_error) < 5 and abs(tilt_error) < 5:curr_corner_index = (curr_corner_index + 1) % 4if curr_corner_index == 0:i += 1time.sleep_ms(100)#如果计时器超过了7秒if clock.avg() > 7000 :curr_corner_index = (curr_corner_index + 1) % 4# 重新开始计时clock.tick()time.sleep_ms(100)if curr_corner_index == 1 and i == 1  :#退回到主函数servo.position(0, 83)servo.position(1, 77)time.sleep_ms(1000)breakprint("Executing Function C")
#寻找红色激光
def find_red(img):#调用全局变量x,yglobal x,yimg = sensor.snapshot()clock.tick()red_td = [(68, 100, 6, 127, 2, 127)]# 根据阈值找到色块for b in img.find_blobs(red_td,pixels_threshold=2, area_threshold=15, merge=True,invert = 0):# 在屏幕上画出色块#img.draw_rectangle(b.rect(), color = (0, 255, 0), scale = 2, thickness = 2)x = b.cx()  # 获取激光中心的x坐标y = b.cy()  # 获取激光中心的y坐标img.draw_cross(x, y, color = (0, 255, 0), size = 1, thickness = 1)  # 在屏幕上画出激光中心#没有读取到激光返回0,0return x,y    
  1. 实际效果还行,就是舵机精度不够,过几天试试拿步进做一个看看效果

发挥部分

  1. 我感觉相对好做的,可以直接拿OpenMV 例程的追小球的云台改,效果还是相当不错的
    做一个红色激光的识别,做一个绿色激光的识别,整体跟基础部分没差多少

import pyb
import sensor, image, timefrom pid import PID
from pyb import Servopan_servo=Servo(1)
tilt_servo=Servo(2)x = 0
y = 0w = 0
h = 0pan_servo.calibration(500,2500,500)
tilt_servo.calibration(500,2500,500)pan_servo.angle(45)
tilt_servo.angle(140)# 初始化键盘行引脚和列引脚
row_pins = [pyb.Pin('P0', pyb.Pin.OUT_PP),  # 行引脚设置为输出
]
col_pins = [pyb.Pin('P1', pyb.Pin.IN, pyb.Pin.PULL_DOWN),  # 列引脚设置为输入,下拉电阻
]# 1x4 键盘布局
keymap = [['1'],
]pan_pid = PID(p=0.07, i=0, imax=90) 
tilt_pid = PID(p=0.05, i=0, imax=90) sensor.reset() # Initialize the camera sensor.s
sensor.set_pixformat(sensor.RGB565) # use RGB565.
sensor.set_framesize(sensor.QQVGA) # use QQVGA for speed.
sensor.skip_frames(10) # Let new settings take affect.
sensor.set_auto_whitebal(False) # turn this off.
clock = time.clock() # Tracks FPS.def find_red(img):#调用全局变量x,yglobal x,yimg = sensor.snapshot()clock.tick()red_td = [(55, 74, 22, 127, -128, 127)]for b in img.find_blobs(red_td,pixels_threshold=2, area_threshold=15, merge=True,invert = 0):img.draw_rectangle(b.rect(), color = (0, 255, 0), scale = 2, thickness = 2)x = b.cx()  # 获取光中心的x坐标y = b.cy()  # 获取光中心的y坐标img.draw_cross(x, y, color = (255, 0, 0), size = 1, thickness = 1)  # 在屏幕上显示红色激光位置return x,ydef find_green(img):global w,himg = sensor.snapshot()clock.tick()red_td = [(81, 97, -128, -3, -128, 127)]for b in img.find_blobs(red_td,pixels_threshold=2, area_threshold=15, merge=True,invert = 0):img.draw_rectangle(b.rect(), color = (0, 255, 0), scale = 2, thickness = 2)w = b.cx()h = b.cy()img.draw_cross(w, h, color = (0, 255, 0), size = 1, thickness = 1)return w,h#在屏幕上显示绿色激光位置
def run():clock.tick() # Track elapsed milliseconds between snapshots().img = sensor.snapshot() # Take a picture and return the image.while True:print("RED ",find_red(img))print("GREEN ",find_green(img))pan_error  = w - xtilt_error = h - y#相对误差print("pan_error: ", pan_error)pan_output=pan_pid.get_pid(pan_error,1 )tilt_output=tilt_pid.get_pid(tilt_error,1)print("pan_output",pan_output)pan_servo.angle(pan_servo.angle()-pan_output+1)tilt_servo.angle(tilt_servo.angle()+tilt_output+1)
def jianpan():for i in range(len(keymap)):# 设置当前行为高电平,其他行为低电平for j in range(len(keymap)):row_pins[j].value(1 if i == j else 0)# 检查列引脚的状态for k in range(len(col_pins)):if col_pins[k].value() == 1:key = keymap[i][k]  # 获取对应的按键字符# 根据按键执行相应的函数if key == '1':run()pyb.delay(10)  # 延时一段时间
while(True):clock.tick() # Track elapsed milliseconds between snapshots().img = sensor.snapshot() # Take a picture and return the image.clock.tick()find_red(img)find_green(img)jianpan()

有一点需要注意的是,红色激光和绿色激光完全重合是是无法判断相对误差的,但是此时error又刚好为0(本人代码能力不行,负负得正了),
红绿激光的读取部分,我将OpenMV(原摄像头)的对焦挑到最大,即使画面是真,由于红绿激光的亮度,在屏幕上能看到像素风格的红色和绿色光斑,计算的中心点和实际的红绿色激光的误差是相对小的(满足小于3cm的附加1要求),抗环境干扰能力是很强的(各种环境没测出识别不出来过)所以说我认为这才是附加题的正解

从理论部分来说,我这两个代码都能完成题目要求,但是实际的精度真的是让人大跌眼镜

我的E题啊


但是我基础3没写死啊!!!(我哭死)
吉林测试第一天晚上下雨啊!!!第二天测试环境真的不行啊啊啊
好了,看到这边给大一的小学弟点个赞不过分吧,求求了
图后面慢慢加吧,晚上先到这了


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部