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
阅读全文
36