扫码加入

  • 方案介绍
  • 相关推荐
申请入驻 产业图谱

2025年电赛E题简易自行瞄准装置(基础发挥全完成)

1小时前
47
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

2025年电赛E题简易自行瞄准装置(基础发挥全完成)

1 系统功能介绍

本系统为“2025年电赛E题简易自行瞄准装置基础”的设计与实现方案,核心目标是在移动小车平台上完成自动寻迹行驶、激光瞄准与击靶任务,并在部分扩展任务中实现激光光斑沿指定轨迹运动的功能。系统以天猛星 MSPM0G3507 开发板为主控,结合二位云台步进电机驱动模块、5 路灰度传感器、OLED 显示屏、AT8236 双路直流电机驱动模块、编码器测速模块、OpenMV 摄像头控制模块以及激光笔控制电路等,构成了完整的运动控制与自动瞄准系统。

在功能实现上,系统满足以下要求:


2 系统电路设计

系统电路设计采用模块化思想,将运动驱动、位置检测、视觉处理、显示、通信与激光控制等部分分离设计,既方便调试,也便于后期功能扩展。

2.1 主控模块——天猛星 MSPM0G3507 开发板

MSPM0G3507 是德州仪器推出的高性能 ARM Cortex-M0+ 内核单片机,主频高、功耗低、外设资源丰富,能够同时处理运动控制与图像数据通信任务。本系统中,主控板主要功能包括:

  • 接收 5 路灰度传感器数据,实现循迹控制算法;
  • 控制 AT8236 驱动模块,实现直流电机正反转与调速;
  • 读取编码器反馈信号,进行速度闭环与位移计算;
  • 与 OpenMV 摄像头通过 UART 通信,接收目标偏差信息;
  • 控制步进电机驱动模块,实现云台二维旋转定位;
  • 控制继电器实现激光笔通断。

2.2 灰度传感器模块

灰度传感器由 5 路 TCRT5000 红外反射式光电开关组成,依次排列在小车前端,负责检测赛道黑白反差。接线关系如下(从左到右):

  • VCC → 5V
  • GND → GND
  • PA30 → L2
  • PA28 → L1
  • PA1 → M0
  • PA0 → R1
  • PA25 → R2

该布局可实现对赛道中心线的偏离量判断,通过 PID 算法动态调整电机输出,保证小车平稳循迹。

2.3 OLED 显示模块

OLED 屏幕用于显示小车运行状态、圈数设定、速度信息等。接线方式:

  • VCC → 5V 或 3.3V
  • GND → GND
  • SCL → PB9
  • SDA → PB8

OLED 模块采用 I2C 通信方式,显示刷新快、功耗低,适合在比赛中实时提供状态信息。

2.4 电机驱动模块——AT8236 双路直流驱动

直流驱动模块负责控制小车两侧驱动轮的直流减速电机。接线方式如下:

  • PWMA、PWMB → 5V
  • PB12 → AIN1
  • PB14 → AIN2
  • PA7 → BIN1
  • PA17 → BIN2
  • STBY → 5V

驱动芯片具备 PWM 调速、方向控制等功能,配合主控 PWM 输出实现平稳加减速与灵活转向。

2.5 编码器测速模块

小车两侧驱动轮各配备一组光电编码器,用于精确测量车轮转速与行驶里程。接线方式:

  • PB5 → 左编码器 A 相 E1A
  • PA10 → 左编码器 B 相 E1B
  • PB4 → 右编码器 A 相 E2A
  • PB15 → 右编码器 B 相 E2B

编码器信号输入主控后,结合定时器输入捕获功能,可实现速度闭环控制

2.6 二位云台步进电机驱动模块

云台结构采用双步进电机驱动,分别实现激光笔的上下和左右方向调整,驱动模块为 D36A 双路步进电机驱动器,供电与直流驱动模块共用电池电源。接线方式:

  • P5 → PA21
  • P7 → DIR2
  • P6 → ST1
  • P9 → DIR1
  • EN1、EN2 → 步进电机驱动 3.3V

2.7 OpenMV 摄像头模块

OpenMV 主要用于目标检测与偏差计算,将识别到的靶心位置偏差数据发送给主控,用于云台定位控制。摄像头采用独立 5V 稳压模块供电,确保图像处理稳定。

2.8 激光笔继电器控制模块

激光笔由继电器实现通断控制,继电器输入端由摄像头 P3 控制,确保仅在发射阶段开启激光。


3 程序设计

程序设计分为运动控制、视觉识别、云台控制和激光控制四大部分。系统采用模块化编程,每个功能模块独立调试,最终在主程序中统一调度。

3.1 主程序框架

主程序负责初始化各硬件模块,进入主循环后根据任务模式执行对应功能。

int main(void)
{
    SYSCFG_DL_init();	        //系统资源配置初始化
    hard_init();               //硬件配置初始化
    OLED_Init();			    //显示屏初始化
    GPIO_Init();			    //蜂鸣器初始化
    params_init();			   //控制参数初始化
    Encoder_Init();				//编码器资源初始化
    Button_Init();				//板载按键初始化
    timer_irq_config();         //定时器中断配置
    usart_irq_config();         //串口中断配置

    while(1)
    {
            TrackControl();
    }
}

3.2 PID算法

float pid_control_dt_run(controller *ctrl,float dt)
{
  float _dt=0;
  get_systime(&ctrl->_time);
  _dt=ctrl->_time.period/1000.0f;
	if(_dt>1.05f*dt||_dt<0.95f*dt||isnan(_dt)!=0)   _dt=dt;
	if(_dt<0.0001f) return 0;

  /*******偏差计算*********************/
	for(uint16_t i=19;i>0;i--)
	{
		ctrl->error_backup[i]=ctrl->error_backup[i-1];
	}
	ctrl->error_backup[0]=ctrl->error;
	
  ctrl->last_error=ctrl->error;//保存上次偏差
  ctrl->error=ctrl->expect-ctrl->feedback;//期望减去反馈得到偏差
	ctrl->dis_error=ctrl->error-ctrl->error_backup[ctrl->dis_error_gap_cnt-1];//微分		ctrl->dis_error=ctrl->error-ctrl->last_error;//原始微分

  if(ctrl->error_limit_flag==1)//偏差限幅度标志位
  {
    if(ctrl->error>= ctrl->error_limit_max)  ctrl->error= ctrl->error_limit_max;
    if(ctrl->error<=-ctrl->error_limit_max)  ctrl->error=-ctrl->error_limit_max;
  }
  /*******积分计算*********************/
  if(ctrl->integral_separate_flag==1)//积分分离标志位
  {
		//只在偏差比较小的时候引入积分控制
    if(ABS(ctrl->error)<=ctrl->integral_separate_limit)	 ctrl->integral+=ctrl->ki*ctrl->error*_dt;
  }
  else
  {
    ctrl->integral+=ctrl->ki*ctrl->error*_dt;
  }
	/*******积分限幅*********************/
	if(ctrl->integral>=ctrl->integral_limit_max)   ctrl->integral=ctrl->integral_limit_max;
	if(ctrl->integral<=-ctrl->integral_limit_max)  ctrl->integral=-ctrl->integral_limit_max;
	
	ctrl->dis_error_lpf=LPButterworth(ctrl->dis_error,&ctrl->lpf_buffer,&ctrl->lpf_params);
		
	/*******总输出计算*********************/
  ctrl->last_output=ctrl->output;//输出值递推
  ctrl->output=ctrl->kp*ctrl->error//比例
							+ctrl->integral//积分
							+ctrl->kd*ctrl->dis_error_lpf;//微分
	
	/*******总输出限幅*********************/
  if(ctrl->output>= ctrl->output_limit_max)  ctrl->output= ctrl->output_limit_max;
  if(ctrl->output<=-ctrl->output_limit_max)  ctrl->output=-ctrl->output_limit_max;
  /*******返回总输出*********************/
  return ctrl->output;
}

3.3 OpenMV 查找图像中的矩形框,绘制中心点

            # 查找图像中的矩形
            for r in img.find_rects(threshold = rect_threshold):
                bos = 1
                bili = r[2]/r[3]
                print("bili==",bili)
                if bili >1.5-0.4 and bili <1.5+0.1:
                    if(r[2] < 110 and r[3] < 70 and r[2] > 13 and r[3] > 10 ):
                        img.draw_rectangle(r.rect(), color = (255, 0, 0))  # 绘制矩形
                        # ===== 添加画中心点 =====
                        center_x = int((r.x() + r.x() + r.w()) / 2)
                        center_y = int((r.y() + r.y() + r.h()) / 2)
                        img.draw_circle(center_x, center_y, 3, color=(0, 0, 255))  
                        i=0
                        # 获取并绘制四个顶点
                        for p in r.corners():
                            img.draw_circle(p[0], p[1], 2, color = (0, 255, 0))
                            points[3-i][0] = p[0]*2
                            points[3-i][1] = p[1]*2
                            i = i + 1

                        r_jiguang_piancha_x = int(jiguang_piancha_x/biaoding_50cm_rect_kuan*r[2])
                        r_jiguang_piancha_y = int(jiguang_piancha_y/biaoding_50cm_rect_kuan*r[2])

                        pan_error = center_x - img.width() / 2 - r_jiguang_piancha_x  # 水平误差
                        tilt_error = center_y - img.height() / 2 - r_jiguang_piancha_y # 垂直误差

                        pan_output = pid_control(pan_error, pan_pid_params, pan_state)
                        tilt_output = pid_control(tilt_error, tilt_pid_params, tilt_state)

                        speed_1 = abs(int(pan_output))
                        speed_2 = abs(int(tilt_output))
                        direction_1 = "cw"
                        direction_2 = "cw"
                        if pan_error > 3 :
                            flag_x = 0
                            direction_1 = "cw"
                            jiguang_pin.low()
                        elif pan_error < -3 :
                            flag_x = 0
                            direction_1 = "ccw"
                            jiguang_pin.low()
                        else:
                            flag_x = 1
                        if tilt_error > 4 :
                            direction_2 = "ccw"
                            flag_y = 0
                            jiguang_pin.low()
                        elif tilt_error < -4 :
                            direction_2 = "cw"
                            flag_y = 0
                            jiguang_pin.low()
                        else:
                            flag_y = 1
                        if flag_x and flag_y:
                            jiguang_pin.high()
                        motor_control(1, speed_1, direction_1)
                        motor_control(2, speed_2, direction_2)

                        print(pan_error," --  ",tilt_error," --  ","Motor1: speed =", speed_1, ", dir =", direction_1,"  Motor2: speed =", speed_2, ", dir =", direction_2)
                    else:
                        bos_num = bos_num + 1
                        if bos_num >30:
                            bos_num = 0
                            bos = 0

4、历年电赛试题解析专栏

  • 点击查看:电赛试题解析汇总:https://blog.csdn.net/m0_51061483/category_10443456.html

5、资料下载

  • 点击下载资料:https://download.csdn.net/download/m0_51061483/91617547

相关推荐