零基础学会制作 基于STM32的电磁炮/2019年电赛E题(获奖作品)/电子设计大赛/OPEN MV/线圈炮/舵机云台/目标追踪

项目介绍

本设计采用模块化的设计思想,电磁炮以STM32为主控核心,由单片机模块、人机交互模块、信息采集模块、舵机模块、电源电压模块、充放电控制模块组成。第一章里介绍了模拟电磁曲射炮的研究背景、现状以及选题意义。第二章介绍了模拟电磁曲射炮的原理分析及整体设计。第三章在电路设计和模块工作原理两个角度对单片机控制模块、信息采集模块、人机交互模块、充放电控制模块、舵机模块、电源电路模块等六大模块进行了系统的介绍,更加清晰的了解各个模块的作用和功能。其中STM32单片机是整个系统的核心,用来协调控制各个模块;Open MV搭配标准M12镜头作为信息采集模块,可以实现颜色识别(红色标识识别)和距离测量,用来搜寻目标靶位置信息,将位置信息通过串口发送至单片机;人机交互模块由输入键盘模块和0.96寸的OLED液晶屏构成,用来显示在不同模式下信息采集模块所采集回来的数据,人机交互模块使用模拟SPI来控制,人机交互模块同时也起到了输入功能,采用4个按键分别执行上、下、确认和返回指令的输入键盘,该按键采用GPIO外部中断读取按键信,可以进行模式选择和数据调整;舵机模块采用舵机驱动的两自由度云台进行炮管的左右角度以及仰角调整。充放电模块采用5A/30V的继电器作为开关,控制电容的充电和放电;电源电路模块经过升压给电容供电,利用boost电路为基础的非隔离式升压模块,可以达到输入12V,输出60~90V的可调电压,输入电流最高达16A,使用12V稳压电源给电容进行充电。第四章主要从各个模块的硬件调试和软件调试对模拟电磁曲射炮的整体系统运行构造进行介绍。

功能介绍

模拟电磁曲射炮的控制算法大致流程如下:整体程序可分为主循环while和一个100ms的定时器。定时器主要用来周期性的让指示灯闪烁,表明程序正常运行,未卡死。
主循环while中的程序分为5个模式:
模式1:UI选择模式1后,电容自动进行充电,并在充完后自动开始放电发射炮弹。
模式2:UI选择模式2后,输入距离,根据距离计算出充电时间Charge_Time,电容开始充电、放电完成炮弹发射。
模式3:UI选择模式3后,输入距离和角度,根据距离计算出充电时间Charge_Time,根据角度计算出云台旋转角度,之后云台先旋转指定角度,最后电容开始充电、放电完成炮弹发射。
模式4:UI选择模式4后,Open MV接通电源开始从中间向正负30度的范围内寻找红色标识,第一步寻找是粗略的寻找,只要视野中出现红色标识,即停止搜索;下一步开始进行精确搜索,这里使用舵机位置式PID进行精确搜索,当误差小于3个像素点时,即可认为舵机处于标识正中位置,停止搜索。之后关闭Open MV传输串口,打开激光测距串口,读取距离,根据距离计算出充电时间Charge_Time,电容开始充电、放电完成炮弹发射。
模式5:UI选择模式5后,首先充电电路接通充好2.5m对应的电量,然后舵机移动到-30度,之后开始在正负30范围内转动;转动过程中一直进行对红色标识中心位置进行读取,当检测到红色标识处于中间位置时,瞬间发射炮弹,在这个过程中,舵机不停止来回运动。

所用模块

本设计是基于单片机来实现模拟电磁曲射炮,控制器采用STM32F103C8T6最小系统板,电容充电电路采用DC/12V的升压电路,发射装置采用电容储能磁阻式线圈,采用Open MV通过对特定颜色的识别目标靶信息,同时搭配MVR系列的激光测距模块,通过串口通信将红色标识信息发送给单片机,单片机控制舵机云台转动,同时单片机控制继电器对储能电容充放电时间进行控制,进而控制发射时由于电磁感应线圈产生的磁力,从而控制炮弹的初速度,可实现任意指定角度和距离的精准打击。整套模拟电磁曲射炮系统经多次调试,可以实现给定角度和距离以及自动识别目标的五种模式下定点一键射击

系统原理图

本设计是基于单片机来实现模拟电磁曲射炮,控制器采用STM32F103C8T6最小系统板,电容充电电路采用DC/12V的升压电路,发射装置采用电容储能磁阻式线圈,采用Open MV通过对特定颜色的识别目标靶信息,同时搭配MVR系列的激光测距模块,通过串口通信将红色标识信息发送给单片机,单片机控制舵机云台转动,同时单片机控制继电器对储能电容充放电时间进行控制,进而控制发射时由于电磁感应线圈产生的磁力,从而控制炮弹的初速度,可实现任意指定角度和距离的精准打击。整套模拟电磁曲射炮系统经多次调试,可以实现给定角度和距离以及自动识别目标的五种模式下定点一键射击,电磁炮整体系统框图如图2.4所示:
在这里插入图片描述

实物图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

部分代码

int main(void)
{
delay_init(); //ÑÓʱº¯Êý³õʼ»¯
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //ÉèÖÃNVICÖжϷÖ×é2:2λÇÀÕ¼ÓÅÏȼ¶£¬2λÏìÓ¦ÓÅÏȼ¶
Key_Init();

OLED_Init();	  //OLED³õʼ»¯
OLED_Clear();
OLED_ShowString(40,0,(uint8_t*)"INIT OK!",12);
more_delay_ms(100); 
Servo_Init();
uart1_init(256000);		
uart2_init(115200);	//¼¤¹â
TIM2_Int_Init(1000-1,7199);//72000000/7200 = 10KhzµÄ¼ÆÊýƵÂÊ£¬
TIM4_Int_Init(1000-1,14399);//¶æ»úPIDÖÜÆÚ

while(key_value!=back)
{ 
	key_read();
	USART_Cmd(USART1, ENABLE);
  USART_Cmd(USART2, ENABLE);
	USART_SendData(USART2, 0x01);
	more_delay_ms(50);					
	OLED_ShowString(5,3, (uint8_t*)"mid=",12);OLED_ShowNum(35,3,middle_x,4,12);		
	OLED_ShowString(5,5, (uint8_t*)"dis=",12);OLED_ShowNum(35,5,Laser_dis-6,4,12);	//-6ÊÇÒòΪ²â¾à¾µÍ·µ½»ų̀×îÇ°¶ËÓÐ6cm
}
key_value=0;OLED_Clear();	
USART_Cmd(USART1, DISABLE);
USART_Cmd(USART2, DISABLE);


while(1)
	{	  
	  Input_UI();//°´¼üUI½çÃæ´¦Àí£¬¶ÁÈ¡ÊäÈëÊý¾Ý
		model_operation();
	}	 

}
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//ʹÄܶ¨Ê±Æ÷2ʱÖÓ
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //ʹÄÜGPIOÍâÉèºÍAFIO¸´Óù¦ÄÜÄ£¿éʱÖÓ

TIM_DeInit(TIM3);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //TIM2_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //¸´ÓÃÍÆÍìÊä³ö
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//³õʼ»¯GPIO

//³õʼ»¯TIM2
TIM_TimeBaseStructure.TIM_Period = arr; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ
TIM_TimeBaseStructure.TIM_Prescaler =psc; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓƵÂʳýÊýµÄÔ¤·ÖƵֵ
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIMÏòÉϼÆÊýģʽ
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //¸ù¾ÝTIM_TimeBaseInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»

//³õʼ»¯TIM2 PWMģʽ	 
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Ñ¡Ôñ¶¨Ê±Æ÷ģʽ:TIMÂö³å¿í¶Èµ÷ÖÆģʽ2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //±È½ÏÊä³öʹÄÜ
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Êä³ö¼«ÐÔ:TIMÊä³ö±È½Ï¼«ÐÔ¸ß

TIM_OCInitStructure.TIM_Pulse=arr/2;//ĬÈÏ50%Õ¼¿Õ±È
TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //¸ù¾ÝTÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIM2 OC2
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //ʹÄÜTIM2ÔÚCCR2ÉϵÄԤװÔؼĴæÆ÷

TIM_OCInitStructure.TIM_Pulse=arr/2;//ĬÈÏ50%Õ¼¿Õ±È
TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //¸ù¾ÝTÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèTIM2 OC2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //ʹÄÜTIM2ÔÚCCR2ÉϵÄԤװÔؼĴæÆ÷

TIM_ARRPreloadConfig(TIM3,ENABLE);
TIM_Cmd(TIM3, ENABLE); //ʹÄÜTIM2
}

// (5%15%25%) *36000 180054009000
void Servo_Init() {
TIM3_PWM_Init(36000-1,20-1);
Servo_Set_Up(DUTY_MID_UP);
Servo_Set_Down(DUTY_MID_DOWN);
}
//0~3600
void Servo_Set_Up(uint32_t pwmDutyUp){
//ÏÞ·ù
pwmDutyUp=uint16_t_Constrain(pwmDutyUp,3400, DUTY_MAX);
TIM_SetCompare1(TIM3,36000-pwmDutyUp);
}

void Servo_Set_Down(uint32_t pwmDutyDown){
//ÏÞ·ù
// pwmDutyDown=uint16_t_Constrain(pwmDutyDown,DUTY_MIN, DUTY_MAX);
TIM_SetCompare2(TIM3,36000-pwmDutyDown);
}

资料下载链接

「实物制作资料.rar」,来自夸克网盘分享。
夸克网盘无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
/a0ef3461vM😕
链接:https://pan.quark.cn/s/75ec9d817bf9
提取码:CtuL

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值