冲刺电赛之电磁炮的制作-控制层2

        久等了,上次说到任务三,自动搜索目标,并进行电磁炮的发射,我们首先要做的是进行一些参数的传递以及变量的初始化。

 代码:

void SHOOT_Init(shoot_move_t *shoot_move_init)
{
	shoot_move_init->shoot_OM_data = get_OM_data_point();//传入openmv数据
	shoot_move_init->shoot_Usart_data = get_Usart1_data_point();//传入openmv数据
	shoot_move_init->offset_x = 0;
	shoot_move_init->offset_y = 0;
	shoot_move_init->ad_value = AD_Value();
	shoot_move_init->shoot_state = SHOOT_PATROL;
	shoot_move_init->distance = GetData(CMD_1);//不用时注释
	shoot_move_init->add_pa = 800;//舵机的初值
	shoot_move_init->add_p_y = 800;
	shoot_move_init->av_distance = 0;
	flag = 0;
	sign = 0;
	sign_shoot = 0;
	RELAY_2(SW_OFF);		
	RELAY_1(SW_OFF);

}

接着就要写循环里面的逻辑了,首先我们要做的第一步是要将用到的数据进行再次更新,

代码:

void shoot_feedback_update(shoot_move_t *shoot_move_update)
{
//	shoot_move_update->shoot_OM_data = get_OM_data_point();//传入openmv数据
//	float add_x = 0;
//	float add_y = 0;
//	add_x = shoot_move_update->shoot_OM_data->OpenMV_X - CENTER_X;
//	add_y = shoot_move_update->shoot_OM_data->OpenMV_Y - CENTER_Y;
	shoot_move_update->offset_x = shoot_move_update->shoot_OM_data->OpenMV_X - CENTER_X;
	shoot_move_update->offset_y = shoot_move_update->shoot_OM_data->OpenMV_Y - CENTER_Y;

	shoot_move_update->sation_x = shoot_move_update->shoot_OM_data->OpenMV_X;
	shoot_move_update->sation_y = shoot_move_update->shoot_OM_data->OpenMV_Y;

	shoot_move_update->ad_value = AD_Value();
	shoot_move_update->dev_x = shoot_move_update->last_sation_x -
	shoot_move_update->sation_x;
	shoot_move_update->dev_y = shoot_move_update->last_sation_y -
	shoot_move_update->sation_y;
	shoot_move_update->distance = GetData(CMD_1);
	shoot_move_update->av_distance = av_distance(shoot_move_update);
	shoot_move_update->key = Key_Scan(GPIOB,GPIO_Pin_12);
	
}

        变量有点多,每一种变量表示什么意思,就不用我再次说明了吧,如果又不懂的,可以私信我,最重要的数据当然是openmv的数据了,这里就衔接这上次讲的内容了,openmv的数据是通过指针的方式传递的。进行状态更新过后,接着就是状态的转换,因为这里设置了两个模式,一个是巡逻模式,一个是射击模式,其中准备发射模式是写在瞄准模式里面的。

typedef enum
{
    SHOOT_PATROL = 0,  //巡逻模式
    SHOOT_AIM,         //瞄准模式
	SHOOT_READY        //准备发射
} shoot_state_t;

        我们要想的就是要定一个条件,进行两种模式的相互切换,我这里是用上位机的数据进行判断的,如果上位机没有识别到目标,上位机通过串口会发送一个0到下位机,也就是这个0,我用来作为状态转换的标志。

代码:

void GIMBAL_sta_management()
{
	
  if( shoot_move.shoot_OM_data->OpenMV_X == 0)
	{
		shoot_move.shoot_state = SHOOT_PATROL;//
		if(sign!=3)
		sign = 1;
		sign_shoot = 0;
	}
	else
	{
		shoot_move.shoot_state = SHOOT_AIM;
		if(sign !=4)
			sign = 2;
	}
//	if(shoot_move.offset_x > -OFFSETMIN_X && shoot_move.offset_x < OFFSETMIN_X)
//	{
//		shoot_move.shoot_state = SHOOT_READY;
//	}
}

接着就是写每种状态里面的代码了,最简单的就是巡逻模式

if(shoot_move_control->shoot_state == SHOOT_PATROL)
	{
		if(sign == 2)
		{
			shoot_move_control->add_pa = shoot_move_control->en_st_x;
			shoot_move_control->add_p_y = shoot_move_control->en_st_y;
		}
			sign = 3;
		/*         X轴限位        */
		if(shoot_move_control->add_pa == X_MAX || shoot_move_control->add_pa > X_MAX)
			flag = 1;
		if(shoot_move_control->add_pa == X_MIN || shoot_move_control->add_pa < X_MIN)
			flag = 0;
		if(flag == 1)
			shoot_move_control->add_pa -= ADD_CE;
		if(flag == 0)
			shoot_move_control->add_pa += ADD_CE;	
		/*          Y 轴限位       */
		if(shoot_move_control->add_p_y == Y_MAX || shoot_move_control->add_p_y > Y_MAX)
			flag_y = 1;
		if(shoot_move_control->add_p_y == Y_MIN || shoot_move_control->add_p_y < Y_MIN)
			flag_y = 0;
		if(flag_y == 1)
			shoot_move_control->add_p_y -= ADD_CE_Y;
		if(flag_y == 0)
			shoot_move_control->add_p_y += ADD_CE_Y;		
	}

其中sign是一个标志位,因为为了使两种模式下舵机值的一个承接,而这个承接又只能运行一次,所以设置了sign这个变量,也是比较巧妙的一个方法,或许还有更好的方法,属于说是在下愚昧了。舵机云台是两自由度的,分为x轴和y轴。接下来就是瞄准模式了,先上代码:

else if(shoot_move_control->shoot_state == SHOOT_AIM)
	{
		shoot_move_control->add_x = 0;
		if(shoot_move_control->offset_x < 0)
		{
			shoot_move_control->add_x +=  ADD_COE_X;
		}
		if(shoot_move_control->offset_x > 0) 
		{
			shoot_move_control->add_x -=  ADD_COE_X;
		}
		if(shoot_move_control->offset_y > 0 )
		{
			shoot_move_control->add_y +=  ADD_COE_Y;
		}
		else 
		{
			shoot_move_control->add_y -=  ADD_COE_Y;
		
		}
		if(shoot_move_control->offset_x > -OFFSETMIN_X && shoot_move_control->offset_x < OFFSETMIN_X)
		{
			shoot_move_control->add_x = 0;
			if(sign_shoot == 0)
			{
				TIM_SetCompare3(TIM4,1000);
				
				shoot_move_control->av_distance = av_distance(shoot_move_control);
 				relay_launch(shoot_move_control);
			}
			delay_ms(10);
			RELAY_2(SW_OFF);		
			RELAY_1(SW_OFF);
			sign_shoot = 1;
		}
		if(shoot_move_control->offset_y > -OFFSETMIN_Y && shoot_move_control->offset_y < OFFSETMIN_Y)
		{
			shoot_move_control->add_y = 0;
		}
		
		if(sign == 2)
		{
			
			shoot_move_control->en_st_x = shoot_move_control->add_pa;
			shoot_move_control->en_st_y = shoot_move_control->add_p_y;	
		}
		
		sign = 4;
		shoot_move_control->en_st_x += shoot_move_control->add_x;
		shoot_move_control->en_st_y += shoot_move_control->add_y;
		if(shoot_move_control->en_st_x == X_MAX || shoot_move_control->en_st_x > X_MAX)
		{
			shoot_move_control->en_st_x = X_MAX;
		}
		if(shoot_move_control->en_st_x == X_MIN || shoot_move_control->en_st_x < X_MIN)
		{
			shoot_move_control->en_st_x = X_MIN;
		}
		if(shoot_move_control->en_st_y == Y_MAX || shoot_move_control->en_st_y > Y_MAX)
		{
			shoot_move_control->en_st_y = Y_MAX;
		}
		if(shoot_move_control->en_st_y == Y_MIN || shoot_move_control->en_st_y < Y_MIN)
		{
			shoot_move_control->en_st_y = Y_MIN;
		}
		delay_ms(10);
		
	}

        通过上位机发送过来的数据,判断目标物处于中心点的那个位置,可以简单的分为4个象限,为了是目标物到达中心点,舵机的运动轨迹可以分为了x和y轴,用到中心点的正负作为转动方向的依据,也是一个比较简单的逻辑判断,再设置了一个变量OFFSETMIN_X,作为一个误差值,因为不可能完完全全到达中心点,由于识别的误差或者种种原因,提高效率,设置了这个变量作为已经到达中心点的依据,只要是+-OFFSETMIN_X范围内,就是到达了中心点,然后进入发射状态。

        其实最重要的忘记说了,就是把值传入到舵机,先上代码:

        

void st_en(shoot_move_t *shoot_move_en)
{

	if(shoot_move_en->shoot_state == SHOOT_PATROL)
	{
		TIM_SetCompare2(TIM4,shoot_move_en->add_pa);
		if(shoot_move_en->key == 0)
			shoot_move_en->add_p_y = 1000;
		TIM_SetCompare3(TIM4,shoot_move_en->add_p_y);
	}//TIM_SetCompare3(TIM4,y);
	else 
	{
		TIM_SetCompare2(TIM4,shoot_move_en->en_st_x);
		if(shoot_move_en->key == 0)
			shoot_move_en->en_st_y = 1000;
		TIM_SetCompare3(TIM4,shoot_move_en->en_st_y);
	}
}

还有一个就是延时函数,普通的延时函数是没办法做到延时很久的,我写了一个延时plus函数,

void delay_puls(int time)
{
	int i = time/1000;
	int j = time - i*1000;
	int times = 0;
	for(;times<i;times++)
	{
		delay_ms(1000);
		
	}
	if(j == 0)
	{
		j = 10;
	}
	delay_ms(j);
}

判断余数j是否为0是为了解决延时0ms的bug,这个会导致程序卡死。

好的,关于电磁炮的代码就到这里了,后续有什么问题可以通过私信或者QQ都行。

QQ:488628560

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值