2019年电赛H题电磁炮实录

2019年电赛H题电磁炮实录

  • 前言
    • 硬件
      • 电磁炮部分
      • 控制部分
        • 模型
        • 结构
    • 软件
      • 交互操作
      • OpenMV
      • STM32
    • 相关资料

前言

你好学弟!这里是学长向你展示他们在2019年夏天搭出来的破烂是如何运行的。老师让我们把这堆破烂留给你们(有些零件缺了你们要自己买 -_-),这边怕你们不懂,完全自愿的给你们写了一篇教程,规避一些我们走过的弯路,也希望你们能把这份精神传承下去,替下下届的接班人们开山铺路。话不多说,先上个实物图。
2019年电赛H题电磁炮实录_第1张图片

硬件

我们搭的这个玩意主要分为两个部分,电磁炮电路部分和控制电路部分,还有一块电源部分,当然其实测试现场是提供学生电源的,我们纯粹是吃饱了撑的。

  1. 电磁炮部分:包括两个开关(一个充电,一个放电),一个高压电容,一个升压模块,一个线圈与炮管。
  2. 控制部分:两个舵机+云台,一块F407(带触控屏),两个继电器,一块OpenMV,一个超声波模块

2019年电赛H题电磁炮实录_第2张图片

电磁炮部分

我们基本是照着这个电路搭建的:

2019年电赛H题电磁炮实录_第3张图片
原理很简单,主要就是控制一个电容的充放电,电磁炮用的是450V/1000uF的高压电容,所以需要用一个升压模块,充电开关就接在电池与升压模块之间。至于放电,把线圈接在电容两边就行了,但是放电开关不能直接接回路里(会烧的),所以加了一个可控硅,也就是一个开关管,当G置高的时候,K&A端就导通了,最后加了一个续流二极管给线圈放电。
现在说起来很简单,当初可是想破了头。。。
上实物图:

这边贴出详细物料清单:

  • 高压绝缘导线:这边一定要用这种线,用的时候截一段两边套热缩管。 淘宝链接
  • 开关两个: 就普通开关 淘宝链接
  • 航模电池:我买的是3S 2200mah的,额定电压11.1V 淘宝链接
  • 可控硅:型号BTA12-600B 淘宝链接
  • 升压模块:DC-DC直流升压模块 45-390V可调 淘宝链接
  • 电容:450V1000UF 电解电容 淘宝链接

注意事项:

  1. 线圈:其实比赛最主要的就是绕线圈,因为比赛是规定了管子直径的,所以线圈要自己拿漆包线( ϕ \phi ϕ 0.5~0.8)绕,绕的厚度,长度太短太薄都不行。线圈底部用棍子什么的封住,让炮弹头正好与线圈尾部重合,这样可以获得最长的加速距离。
    2019年电赛H题电磁炮实录_第4张图片
    2019年电赛H题电磁炮实录_第5张图片
    2019年电赛H题电磁炮实录_第6张图片
    2019年电赛H题电磁炮实录_第7张图片
  2. 充电开关和放电开关不能同时按!!还有每次充电之前都要先按下放电开关给电容放电,确保是从头开始充电的!!
  3. 升压模块:其实这个升压模块还是比较容易坏的,那个保险丝比较容易烧,要多备一些保险丝,模块上面有一个可调电阻可以调节输出电压,一般来讲在相同充电时间下充电电压越高电磁炮平射的距离越远,我们一般调节在100V左右。
    2019年电赛H题电磁炮实录_第8张图片
  4. 涉及到电磁炮射出炮弹的距离,有好几个可以调节的量。例如电容的充电时间,充电电压,炮口仰角。其实电容充电时间和充电电压就是决定的炮口初速度大小,根据我们的计算,电容充电在零点几秒之内就能完成,所以主要就是旋那个调节电阻改变充电电压,然后根据经验得到一个合适的出射速度V。当然这边其实可以在炮口加一个光电门测速,这样更精确一些。
  5. 炮弹:关于炮弹,当初实验室里用各种各样的都有,最基本的是小钢珠,还有小磁铁块,经过验证磁铁块是比小钢珠射的更远一些。不过最后我们选的是无头螺钉,效果也不错。
  6. 续流二极管:我们是直接焊在线圈两端,方向一定不能弄反 淘宝链接,挑大规格的买就行。
    2019年电赛H题电磁炮实录_第9张图片
    2019年电赛H题电磁炮实录_第10张图片

控制部分

模型

其实基本模型就是中学的抛体公式:
2019年电赛H题电磁炮实录_第11张图片
假设炮弹初速度为V,炮口相对于地面倾角为α,炮口相对于地面的竖直落差为h,重力加速度为g,取g = 9.8N/kg。
将炮弹的速度分解为水平与竖直两个方向上的分速度,分别为Vx=V *Cosα和Vy = V * Sinα。此时炮弹落地所需时间为:
t = − V y + ( V y 2 + 2 g h ) g t= \frac{-V_y+\sqrt {(V_y^2+2gh)}}{g} t=gVy+(Vy2+2gh)
炮弹在水平方向的距离方程为:
s = V ∗ c o s α ∗ t s =V *cosα * t s=Vcosαt
炮弹在竖直方向的距离方程为:
y = V s i n α − 1 2 g t 2 y=V sinα-\frac{1}{2} gt^2 y=Vsinα21gt2
由此可得出射角度α与距离s的关系式:
− h = s ∗ t a n α − 1 2 g ( s V c o s α ) 2 ( ∗ ) -h=s*tanα- \frac{1}{2} g(\frac{s}{V cosα })^2(*) h=stanα21g(Vcosαs)2
这边当时我们通过调节升压模块上的可调电阻得到一个确定的电压(90~100V左右)与炮口初速,然后通过调节仰角α来改变距离s。
这边有两种思路:

  • 一种是通过纯数学公式模拟整个模型,得出α(x)与s(fx)的关系式,进而确定每次的仰角。用matlab数值模拟将( ∗ * )式解出,V取平射能达到两米时的初速,h由题目给定。
    2019年电赛H题电磁炮实录_第12张图片
  • 另一种是直接枚举出所有距离下对应的炮口仰角,然后直接存在程序里调用。这种方式精确度很高,但需要大量的测试,一遍遍的调整角度然后记录距离。
    在电赛过程中如果时间充裕的话一般都是用枚举,老师可不会关心你用了什么多先进的算法模型,而是只关心结果!!

结构

系统的总体框图如下:
2019年电赛H题电磁炮实录_第13张图片

  • 主控模块:选用一块STM32F407带一块触控屏作为交互2019年电赛H题电磁炮实录_第14张图片
    2019年电赛H题电磁炮实录_第15张图片
  • 执行模块:用了两个舵机和一个双轴云台架 2019年电赛H题电磁炮实录_第16张图片
  • 测距模块:测距与识别模块用到的是openMV和超声波,openMV用于识别红色目标靶,超声波用于测量与靶子的距离。2019年电赛H题电磁炮实录_第17张图片
    2019年电赛H题电磁炮实录_第18张图片
  • 继电器模块:通过两路继电器模块控制充电与放电开关,这里需要选导通电压12V的
    2019年电赛H题电磁炮实录_第19张图片
    2019年电赛H题电磁炮实录_第20张图片
  • 电源模块:选用充电宝+USB集线器给OpenMV与F407供电,一块额定电压11V的电池输出两路分别给继电器供电以及到一块降压模块中转成舵机使用的7V

    降压模块的特写:输入12.31V,输出6.63V,按下on/off开启输出,开启输出后舵机不能再用手硬拨了!
    2019年电赛H题电磁炮实录_第21张图片
    2019年电赛H题电磁炮实录_第22张图片

器件清单:

  • STM32F407:由于这边用的是正点原子的例程,需要能兼容正点原子屏的开发板 淘宝链接
  • 舵机云台:U型梁支架x2,金属舵盘x2,杯式轴承x2,脚板支架x1,长U支架x1,短U支架x1,多功能支架x2 淘宝链接 淘宝链接
  • OpenMV与超声波:壳与镜头要另买 淘宝链接 淘宝链接
  • 电源模块:淘宝链接 淘宝链接 淘宝链接 淘宝链接

软件

代码分为OpenMV部分和STM32部分,OpenMV用于进行色块识别,STM32用于主控以及交互。这边先讲解如何交互,然后再简略讲解一下代码结构。整个工程我也会放上来。

交互操作

所有操作都在这个正点原子电阻屏上完成。一开始进入时需要进行屏幕校准,一般情况下屏幕校准只需要进行一次就可,然而这边有一个我们一直没能解决的BUG,开发板上默认是不带24C02的,所以我们焊了一个上去,然而这个24C02在代码里始终无法初始化成功,不知道怎么回事。
2019年电赛H题电磁炮实录_第23张图片
进入程序界面:可选择操作模式,其中模式一用于指定角度与距离的射击,模式二用于识别红色标靶与距离并进行射击,模式三用于摆动射击。下方为调试信息。
2019年电赛H题电磁炮实录_第24张图片
模式一:上方两排分别对应百十个位的加减;Swtch用于切换设置距离或角度;Negti用于设置角度的正负,以炮口正对向前为0度;Start键开始射击;Retrn返回,有时候不太灵,需要重启一下
2019年电赛H题电磁炮实录_第25张图片
模式二:有两个Start,分别对应摄像头测距与超声波测距,点左边那个。红色靶就按题目中给定的做。
2019年电赛H题电磁炮实录_第26张图片
模式三:就一个Start,点击过后会开始从-20°到+20°开始搜寻标靶,当搜寻到时会立即射出炮弹。
2019年电赛H题电磁炮实录_第27张图片

OpenMV

安装OpenMV IDE以及快速入门:参考链接

#提示包未安装的自己找教程安装一下-_-
import sensor, image, time, math
from pyb import UART
import json	
import ustruct

sensor.reset()
sensor.set_framesize(sensor.QVGA)
sensor.set_pixformat(sensor.RGB565)
sensor.skip_frames(time = 2000)
#sensor.set_auto_gain(False) # must be turned off for color tracking
#sensor.set_auto_whitebal(False) # must be turned off for color tracking
#sensor.set_auto_exposure(False,2000);  #控制曝光时间,单位为us
sensor.set_hmirror(True); #控制水平镜像翻转
sensor.set_vflip(True); #控制水平镜像翻转
#sensor.set_windowing((22,7,110,105));

clock = time.clock()
uart = UART(3,115200)   #定义串口3变量    P4 TX<-->PA10  P5 RX<-->PA9
uart.init(115200, bits=8, parity=None, stop=1) # init with given parameters

#binary_threshold = (0, 156)
find_threshold = (51, 77, 34, 67, -33, 50)
K = 12800;  #自己选取一个合适的校准值
def find_max(blobs):    #定义寻找色块面积最大的函数
    blobs.sort(key=lambda x:x.pixels(),reverse=True);
    max_blob={}             #默认为空字典
    length=len(blobs);
    if length>0:
        max_blob=blobs[0];
    return max_blob;

def sending_data(cx_max,cy_max):
    global uart;
    #frame=[0x2C,18,cx%0xff,int(cx/0xff),cy%0xff,int(cy/0xff),0x5B];
    #data = bytearray(frame)
    data = ustruct.pack(",              #格式为俩个字符俩个短整型(2字节)
                   0x2C,                       #帧头1
                   0x12,                       #帧头2
                   int(cx_max), # up sample by 4    #数据1
                   int(cy_max), # up sample by 4    #数据2LCD_ShowStringLCD_ShowString
                   0x5B);
    uart.write(data);   #必须要传入一个字节数组

while(True):
    clock.tick()
    img = sensor.snapshot()#.lens_corr(1.45);
    #img.binary([binary_threshold], invert = 1)
    blobs = img.find_blobs([find_threshold],area_threshold=150)

    if blobs:	#如果找到的话
        max_blob=find_max(blobs)
        img.draw_rectangle(max_blob.rect(),color=(0,0,255))
        img.draw_cross(max_blob.cx(), max_blob.cy(),color=(0,0,255))
        img.draw_cross(160, 120,color=(0,0,255)) # 在中心点画标记
        img.draw_line((160,120,max_blob.cx(),max_blob.cy()), color=(0,0,255));

        phi = (max_blob.w() + max_blob.h())/2;
        length = K/phi; #获得距标靶距离

        #print('position:',max_blob.cx(),max_blob.cy())
        if(max_blob.pixels()>1000):	#滤除像素过小的干扰
            sending_data(max_blob.cx(),length); #发送点位坐标
            #print(max_blob.pixels())
        print("Length=",length);
    else:
        sending_data(10000,10000);
    #print(clock.fps())

STM32

开发环境:Keil v5以及相应的F4XX器件包,Keil v4不知道会不会报错。

//这里就简要的说明一下各个文件的内容
//具体工程我放到百度云里了-_-

/*
main.c:
包含所有的变量定义,所有的初始化,
主循环while(1)用于模式切换以及数据通信
主要控制逻辑中断函数void TIM3_IRQHandler(void)频率50Hz,用于处理各个模式下的具体执行

usart2.c:
用于处理与OpenMV的通信

timer.c:
定时器3的初始化

pwm.c:
定时器14,11,4的初始化

Control.c:
对串口2接收的数据进行处理
对舵机的PID控制函数

Interface.c:
各个模式交互界面的编写

jidianqi.c:
继电器的初始化

US100.c:
超声波的所有相关

24cxx.c
ctiic.c
myiic.c
touch.c
ft5206.c
gt9147.c
ott2001.c
*/

相关资料

工程链接:
百度云:https://pan.baidu.com/s/1Z5I1Z38kK1VSa_iRjeXQYQ 提取码:wbrp

CSDN:https://download.csdn.net/download/qq_43243338/11938761

模块资料:
找淘宝店家要…

你可能感兴趣的:(openMV,电磁炮)