2024年 TI杯 全国电子设计大赛 H题省一方案 (附源码)


题目规定必须使用TI板子MSPM0 系列 MCU 控制,不得采用其他型号的 MCU。
我的方案在灰度识别,电机上有其他芯片,在极少数赛区(3个左右,如天津)会判违规。
为何使用带有其他mcu的模块,考虑到历年电赛不禁止皆可为的形式,判断 “必须使用TI板子MSPM0 系列 MCU 控制” 其目的是为了防止MSP点灯,其他mcu主控的情况,而得出赛方会对模块自带的mcu宽容处理的结果。

一.设计思路

题目难点

审题之后,我们可以得到一个结论,这道题的最难点为:
MSPM0系列板子为2023年中推出,距离比赛的2024年7月,刚好为一年,TI板受众也没有STM广泛,导致网上资料少,社区支持少,4天3夜从0开始学习这块板子时间紧任务重。
所以在方案的设计上,简单易上手则成为重中之重。

方案设计

赛道分为有线赛道和无线赛道,有线赛道,毫无疑问使用多路灰度传感器来识别黑线赛道来控制转弯,很多人会在里面加入PID算法让行进更湿滑,但是对于题目中这种简单的圆弧寻迹,使用if else更简单更快速,包括进出线的检测也是如此。
重点是接下来的无线行进,大多数人使用陀螺仪+直流电机或编码器+直流电机来控制车身姿态,其原因是,直流电机会因为不同电源电压,电机电枢绕组老化程度不同等问题导致不能同步,从而需要陀螺仪或编码器闭环控制。而我们打算使用步进电机,步进电机在负载不大,速度不高的情况下,几乎不会丢步,这就可以让小车不依靠更多的传感器完成既定路线行进。

遇到的问题

在设计路线时,因为弯道出线时角度会有不同,导致直线行驶的目的地会有一定偏差,为了减少偏差,我们加入了弧线行驶和s型行驶,这样可以更好的入线。
当时在我完成题目除蜂鸣器外的所有要求后,打算使用嘀嗒定时器来触发蜂鸣器,但使用滴答定时器后不知为何发生了堵塞,导致原定路线发生偏移,考虑到时间问题,我们并没有花费过多时间解决这个问题,而是采用了第二块MSPM0,通过简单的io翻转电平通讯让其响应,从物理上隔离了堵塞对主控的影响。

方案优点

绝大多数的方案为:MSPM0+直流电机+陀螺仪+灰度传感器+蜂鸣器
我的方案为:MSPM0+步进电机+灰度传感器+蜂鸣器
因为不使用陀螺仪/编码器闭环控制,而使用步进电机,所以我们不需要使用IIC,PID,也不需要处理陀螺仪的数据,飘零等现象,可以节省大量时间。

二.程序源码

GitHub:https://github.com/GreatWhiteShark-dbs/TI-Cup-2024-H-Line-Following-Car

<think>我们参考引用内容,用户提到的是使用MSPM0G3507实现四路红外寻迹功能。根据引用[2]和[3],他们使用了8路灰度传感器(也就是红外寻迹传感器)来实现巡线。现在用户想要实现四路红外寻迹,方法类似,只是传感器数量减少为4个。 实现思路: 1. 硬件连接:将四个红外寻迹传感器连接到MSPM0G3507的ADC输入引脚(如果传感器输出的是模拟信号)或者GPIO(如果传感器输出的是数字信号)。通常情况下,红外寻迹传感器有模拟输出和数字输出两种,但常见的是数字输出(即遇到黑线输出低平,白线输出高平,或者相反,取决于传感器设计)。这里我们假设使用的是数字输出的红外传感器。 2. 传感器布局:将四个红外传感器并排安装在小车的前方,从左到右分别为Sensor1、Sensor2、Sensor3、Sensor4。相邻传感器之间的距离应略小于指示线的宽度,以保证能够检测到黑线。 3. 读取传感器状态:通过读取四个传感器的状态,可以判断小车相对于黑线的位置。例如: - 0000:没有检测到黑线(可能全部在白色区域,或者全部悬空) - 0010:中间两个传感器检测到黑线,说明小车在直线上(理想状态) - 0001:最右边的传感器检测到黑线,说明小车偏左,需要向右调整 - 1000:最左边的传感器检测到黑线,说明小车偏右,需要向左调整 - 等等 4. 控制策略:根据传感器状态,控制小车的左右轮速度,实现转向。可以使用简单的逻辑控制,也可以使用PID控制(如引用[2][3]中提到的串行PID)。 5. 具体实现步骤: a. 初始化MSPM0G3507的GPIO(用于读取数字信号)或ADC(如果使用模拟信号)。 b. 在循环中不断读取四个传感器的状态。 c. 根据状态,计算出小车的偏离情况,然后调整左右机的速度。 d. 驱动机(通过PWM控制机驱动模块)。 注意:如果传感器是模拟输出,则需要使用ADC读取模拟压值,然后通过设定阈值来判断是否检测到黑线。 代码框架(伪代码): ```c #include <ti/devices/msp/msp.h> #include "ti_msp_dl_config.h" // 假设四个红外传感器分别连接到P1.0, P1.1, P1.2, P1.3 (数字输入) #define SENSOR1_PORT GPIO_PORT(1) #define SENSOR1_PIN GPIO_PIN(0) #define SENSOR2_PORT GPIO_PORT(1) #define SENSOR2_PIN GPIO_PIN(1) #define SENSOR3_PORT GPIO_PORT(1) #define SENSOR3_PIN GPIO_PIN(2) #define SENSOR4_PORT GPIO_PORT(1) #define SENSOR4_PIN GPIO_PIN(3) // 初始化GPIO void init_GPIO(void) { // 将四个引脚配置为输入 DL_GPIO_setPinsInput(SENSOR1_PORT, SENSOR1_PIN); DL_GPIO_setPinsInput(SENSOR2_PORT, SENSOR2_PIN); DL_GPIO_setPinsInput(SENSOR3_PORT, SENSOR3_PIN); DL_GPIO_setPinsInput(SENSOR4_PORT, SENSOR4_PIN); } // 读取传感器状态,返回个4位的值,每位代表个传感器的状态(0或1) // 注意:根据实际硬件,可能需要取反(因为有些传感器检测到黑线输出低平) uint8_t read_sensors(void) { uint8_t state = 0; // 读取第个传感器 if (DL_GPIO_readPins(SENSOR1_PORT, SENSOR1_PIN) == 0) { // 假设低平表示检测到黑线 state |= 0x01; // 0001 } if (DL_GPIO_readPins(SENSOR2_PORT, SENSOR2_PIN) == 0) { state |= 0x02; // 0010 } if (DL_GPIO_readPins(SENSOR3_PORT, SENSOR3_PIN) == 0) { state |= 0x04; // 0100 } if (DL_GPIO_readPins(SENSOR4_PORT, SENSOR4_PIN) == 0) { state |= 0x08; // 1000 } return state; } // 根据传感器状态控制机 void control_motors(uint8_t sensor_state) { // 这里只是个简单的示例,实际控制策略需要根据小车调试情况调整 switch(sensor_state) { case 0x00: // 0000 没有检测到线,可以停止或者按照上次的方向继续 // 停止或者使用其他策略 break; case 0x01: // 0001 只有最右边传感器检测到,说明线在右边,需要向右转 // 左轮前进,右轮停止或后退 break; case 0x02: // 0010 中间偏右检测到,轻微右转 break; case 0x04: // 0100 中间偏左检测到,轻微左转 break; case 0x08: // 1000 只有最左边传感器检测到,说明线在左边,需要向左转 // 右轮前进,左轮停止或后退 break; case 0x03: // 0011 右边两个传感器检测到,需要向右转 break; case 0x0C: // 1100 左边两个传感器检测到,需要向左转 break; case 0x06: // 0110 中间两个传感器检测到,直行 break; // 其他情况... } } int main(void) { // 系统初始化 init_GPIO(); // 初始化机控制(PWM等) while(1) { uint8_t sensor_state = read_sensors(); control_motors(sensor_state); // 延时或等待 } } ``` 注意:上述代码只是个框架,具体实现需要根据硬件连接和实际调试情况进行调整。 另外,引用[2][3]中提到他们使用了串级PID控制,如果用户希望更精确的控制,可以参考以下思路: - 将传感器状态转换为个误差值。例如,定义中间两个传感器的中心为0,当传感器检测到黑线时,根据位置计算误差。比如四个传感器从左到右位置为-3,-1,1,3(单位可以是厘米),当检测到黑线时,取所有检测到黑线的传感器位置的平均值作为当前误差。 - 然后使用PID控制器根据误差计算转向的调整量(比如左右轮速度差)。 例如: - 如果只有最左边的传感器检测到,误差=-3 - 如果只有中间两个检测到,误差=( -1 + 1 ) / 2 = 0 - 如果最右边两个检测到,误差=(1+3)/2=2 然后使用PID控制器: adjustment = Kp * error + Ki * integral_error + Kd * derivative_error; 然后控制左右轮速度: left_speed = base_speed - adjustment; right_speed = base_speed + adjustment; 这样就能实现个比例控制,使小车尽量保持在黑线中央。 总结:四路红外寻迹的实现主要分为硬件连接、传感器状态读取、控制策略(逻辑控制或PID控制)和机驱动四个部分。 相关问: 1. 如何调整红外寻迹传感器的灵敏度? 2. 四路红外寻迹和八路红外寻迹在控制上有何不同? 3. 如何避免小车在寻迹过程中出现振荡? 4. 使用MSPM0G3507的ADC功能读取模拟红外传感器应该注意什么?</think>### MSPM0G3507 四路红外寻迹实现方法 #### 1. 硬件连接 - **传感器选择**:使用4个数字输出型红外寻迹传感器(如TCRT5000),输出信号为高低平(检测到黑线时输出低平) - **接口分配**: - 传感器1 → MSPM0G3507 GPIO P1.0 - 传感器2 → MSPM0G3507 GPIO P1.1 - 传感器3 → MSPM0G3507 GPIO P1.2 - 传感器4 → MSPM0G3507 GPIO P1.3 - **布局要求**:传感器间距15-20mm(小于黑线宽度),安装高度10-15mm #### 2. 软件实现 ```c // 初始化GPIO(使用TI驱动库) void init_IR_Sensors(void) { DL_GPIO_initDigitalInput(GPIOA, GPIO_PIN_0); // S1 DL_GPIO_initDigitalInput(GPIOA, GPIO_PIN_1); // S2 DL_GPIO_initDigitalInput(GPIOA, GPIO_PIN_2); // S3 DL_GPIO_initDigitalInput(GPIOA, GPIO_PIN_3); // S4 } // 读取传感器状态(0:检测到黑线, 1:未检测) uint8_t read_IR_sensors(void) { return (DL_GPIO_readPins(GPIOA, GPIO_PIN_0) << 0) | (DL_GPIO_readPins(GPIOA, GPIO_PIN_1) << 1) | (DL_GPIO_readPins(GPIOA, GPIO_PIN_2) << 2) | (DL_GPIO_readPins(GPIOA, GPIO_PIN_3) << 3); } // 巡线控制逻辑 void line_following_control(void) { uint8_t sensor_state = read_IR_sensors(); switch(sensor_state) { case 0b0110: // 0010 中间两个检测到 set_motor_speed(LEFT, 100); // 直行 set_motor_speed(RIGHT, 100); break; case 0b1100: // 1000 左侧检测到 set_motor_speed(LEFT, 70); // 右转 set_motor_speed(RIGHT, 100); break; case 0b0011: // 0001 右侧检测到 set_motor_speed(LEFT, 100); // 左转 set_motor_speed(RIGHT, 70); break; case 0b1000: // 最左检测到 set_motor_speed(LEFT, 40); // 急右转 set_motor_speed(RIGHT, 100); break; case 0b0001: // 最右检测到 set_motor_speed(LEFT, 100); // 急左转 set_motor_speed(RIGHT, 40); break; default: // 无检测或异常 search_line(); // 寻线恢复算法 } } ``` #### 3. 关键实现要点 1. **传感器校准**: - 上时自动校准:读取白色背景和黑色指示线的阈值 ```c void calibrate_sensors(void) { uint32_t white_sum = 0, black_sum = 0; // 采集白色区域样本 for(int i=0; i<50; i++) white_sum += read_IR_sensors(); // 采集黑线区域样本 for(int i=0; i<50; i++) black_sum += read_IR_sensors(); threshold = (white_sum + black_sum) / 100; // 计算动态阈值 } ``` 2. **抗干扰处理**: - 添加软件消抖(连续3次相同状态才响应) - 环境光补偿:使用PWM动态调整红外发射强度 ```c DL_Timer_PWM_setDutyCycle(TIMER_0, PWM_0, ambient_light_adjust()); ``` 3. **PID优化**(可选): - 将传感器状态转换为位置误差: $$ error = \frac{(0 \times s1) + (1 \times s2) + (2 \times s3) + (3 \times s4)}{s1+s2+s3+s4} - 1.5 $$ - 实现位置式PID控制: $$ output = K_p \times error + K_i \times \sum error + K_d \times (error - last\_error) $$ #### 4. 调试建议 1. 使用OLED显示实时传感器状态和误差值[^3] 2. 通过串口输出调试数据: ```c printf("Sensors: %d%d%d%d | Error: %.2f\n", s1, s2, s3, s4, position_error); ``` 3. 按键控制PID参数调整[^3]: - KEY1:增加比例系数 $K_p$ - KEY2:增加积分系数 $K_i$ #### 5. 性能优化 1. **中断采样**:使用定时器中断触发采样(推荐100Hz) 2. **DMA传输**:配置DMA将GPIO状态直接传输到内存 3. **低功耗设计**:在直道段启用休眠模式,通过传感器中断唤醒 > **注意事项**:实际安装时需确保传感器与地面平行,避免光源直射。若遇到复杂路径(如十字交叉),需结合编码器距离检测[^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值