扫码加入

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

2024年全国大学生电子设计竞赛H题-自动行驶小车MSP430

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

24年电赛H题-自动行驶小车MSP430

  • 1、赛题回顾
  • 2、电路图设计
  • 3、系统程序设计
  • 4、资料下载
  • 5、历年电赛试题解析专栏

1、赛题回顾

 

2、电路图设计

  • 主控模块是整个系统的核心,题目指定使用TI MSPM0系列MCU,因其具备更丰富的外设资源,例如支持编码器输入的定时器和更多的GPIO接口。由于该芯片的定时器资源有限,若需同时处理电机编码器反馈和系统定时任务,可能需要通过软件模拟或外部中断扩展功能。
  • 传感器模块的设计直接影响小车的路径识别和姿态控制。循迹部分可采用多路红外对管灰度传感器,以检测场地上的黑色半圆弧线。为了提高检测精度,传感器应均匀分布在小车底部,并适当调整安装高度以避免环境光干扰。
  • 电机驱动模块需要保证小车在直线和弯道行驶时的动力响应。由于题目禁止使用履带,推荐采用直流减速电机搭配编码器,以实现闭环速度控制。电机驱动芯片可选择DRV8833或TB6612等H桥驱动,支持PWM调速和正反转控制。编码器信号可通过主控的定时器捕获或外部中断读取,若资源不足,可采用分时复用策略,例如在直线行驶时优先处理速度环PID计算,进入弯道时切换至角度环控制。
  • 声光提示模块主要用于任务要求的反馈功能,例如到达关键点时的蜂鸣器鸣叫和LED闪烁。这部分设计较为简单,可通过主控的GPIO直接驱动蜂鸣器和LED,但需注意蜂鸣器的驱动电流可能超过MCU引脚的最大输出能力,因此建议增加三极管MOS管作为开关。此外,声光信号的频率和持续时间应清晰可辨,避免与其他电子信号产生干扰。

3、系统程序设计

3.1、PID设计


pid_t motorA;
pid_t motorB;
pid_t angle;

int left_encoder,right_encoder;
extern unsigned int Temp[2];
int A_turn,B_turn;


void pid_init(pid_t *pid, uint32_t mode, float p, float i, float d)
{
	pid->pid_mode = mode;
	pid->p = p;
	pid->i = i;
	pid->d = d;
}


void motor_target_set(int spe1, int spe2)
{
	if(spe1 >= 0)
	{
		motorA_dir = 1;
		motorA.target = spe1;
	}
	else
	{
		motorA_dir = 0;
		motorA.target = -spe1;
	}
	
	if(spe2 >= 0)
	{
		motorB_dir = 1;
		motorB.target = spe2;
	}
	else
	{
		motorB_dir = 0;
		motorB.target = -spe2;
	}
}

void pid_cal(pid_t *pid)
{
	// 计算当前偏差
	pid->error[0] = pid->target - pid->now;

	// 计算输出
	if(pid->pid_mode == DELTA_PID)         // 增量式
	{
		pid->pout = pid->p * (pid->error[0] - pid->error[1]);
		pid->iout = pid->i * pid->error[0];
		pid->dout = pid->d * (pid->error[0] - 2 * pid->error[1] + pid->error[2]);
		pid->out += pid->pout + pid->iout + pid->dout;
	}
	else if(pid->pid_mode == POSITION_PID)  // 位置式
	{
		pid->pout = pid->p * pid->error[0];
		pid->iout += pid->i * pid->error[0];
		pid->dout = pid->d * (pid->error[0] - pid->error[1]);
		pid->out = pid->pout + pid->iout + pid->dout;
	}

	// 记录前两次偏差
	pid->error[2] = pid->error[1];
	pid->error[1] = pid->error[0];
	
}

void pid_out_limit(pid_t *pid)
{
	 	// 输出限幅
	if(pid->out>=MAX_DUTY)	
		pid->out=MAX_DUTY;
	if(pid->out<=-MAX_DUTY)	
		pid->out=-MAX_DUTY;
}

void check(int target)
{
	 	  if(target<0) 
	{
		  if(yaw_angle_int<0) yaw_angle_int=yaw_angle_int;
		  else yaw_angle_int=yaw_angle_int-360;
	}
	else if(target>0)
	{
		 if(yaw_angle_int>0) yaw_angle_int=yaw_angle_int;
		else yaw_angle_int=yaw_angle_int+360;
	}
}


void turn_pid(int base,int target)
{
	angle.now=yaw_angle_int;
	angle.target=target;
	pid_cal(&angle);
	motorA.now=left_encoder;
	motorA.target=base-angle.out;
	motorB.now=right_encoder;
	motorB.target=base+angle.out;
	pid_cal(&motorA);
	pid_cal(&motorB);
	pid_out_limit(&motorA);
	pid_out_limit(&motorB);
		
	Set_left_pwm((int)motorA.out);
    Set_right_pwm((int)motorB.out);
	
}

void speed_pid(int target)
{
		  motorA.now=left_encoder;
		  motorA.target=target;
		  pid_cal(&motorA);
			motorB.now=right_encoder;
		  motorB.target=target;
		pid_cal(&motorB);
		Set_left_pwm((int)motorA.out);
	  Set_right_pwm((int)motorB.out);
}


void track_pid(int temp)
{
	  motorA.error[0]=temp;
	  motorB.error[0]=temp;
	  pid_cal(&motorA);
	  pid_cal(&motorB);
}

4.2、编码器程序

//读取编码器计数值
int read_encoder1(void)
{
	int num;
	num = Encoder_count1; //读取计数值
	Encoder_count1 = 0;   //计数值清零
	return num;
}

int read_encoder2(void)
{
	int num;
	num = Encoder_count2; //读取计数值
	Encoder_count2 = 0;   //计数值清零
	return num;
}

// 外部中断
void GROUP1_IRQHandler(void)//Group1的中断服务函数
{
	
  if(GPIOA->CPU_INT.MIS & DL_GPIO_PIN_12) // PA12外部中断   A上升沿
		{
			if(gpio_get(GPIOA, DL_GPIO_PIN_13)==0)       //B 逻辑低
			{
				Encoder_count1 ++;
			}
			else
			{
				Encoder_count1 --;
			}

			GPIOA->CPU_INT.ICLR |= DL_GPIO_PIN_12; // 清除中断标志位
		}
		
		  if(GPIOA->CPU_INT.MIS & DL_GPIO_PIN_13) // PA13外部中断   B相下降沿
		{
			if(gpio_get(GPIOA, DL_GPIO_PIN_12)==0)   // A 逻辑低
			{
				Encoder_count1 ++;
			}
			else
			{
				Encoder_count1 --;
			}

			GPIOA->CPU_INT.ICLR |= DL_GPIO_PIN_13; // 清除中断标志位
		}
		
		if(GPIOA->CPU_INT.MIS & DL_GPIO_PIN_24) // PA24外部中断   A相上升沿
		{
			if(gpio_get(GPIOA, DL_GPIO_PIN_15)==0)      	//B逻辑低
			{
				Encoder_count2 ++;
			}
			else
			{
				Encoder_count2 --;
			}
			
			GPIOA->CPU_INT.ICLR |= DL_GPIO_PIN_24; // 清除中断标志位
		}
		
			if(GPIOA->CPU_INT.MIS & DL_GPIO_PIN_15) // PA15外部中断   B相下降沿
		{
			if(gpio_get(GPIOA, DL_GPIO_PIN_24)==0)    //A逻辑低
			{
				Encoder_count2 ++;
			}
			else
			{
				Encoder_count2 --;
			}
			
			GPIOA->CPU_INT.ICLR |= DL_GPIO_PIN_15; // 清除中断标志位
		}
		
      if(GPIOA->CPU_INT.MIS & DL_GPIO_PIN_17) // PA14外部中断
		 {
        delay_ms(10);
        mode++;
        set=0;
        mode = (mode + 1) % 5;

        GPIOA->CPU_INT.ICLR |= DL_GPIO_PIN_17; // 清除中断标志位
		}
		
		  if(GPIOA->CPU_INT.MIS & DL_GPIO_PIN_27) // PA14外部中断
		{
			delay_ms(10);
			set = (set + 1) % 2;
			GPIOA->CPU_INT.ICLR |= DL_GPIO_PIN_27; // 清除中断标志位
		}
}

	
	

4、资料下载

  • https://download.csdn.net/download/m0_51061483/91458428

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

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

相关推荐