【电子设计大赛】2022电子设计大赛C题通关指南

目录

一、电赛 C 题初印象

二、题目深度剖析

(一)功能要求拆解

(二)技术难点分析

三、硬件基础搭建

(一)小车选型要点

(二)传感器布局与原理

四、软件代码核心实现

(一)整体代码架构设计

(二)循迹功能代码

(三)速度控制代码

(四)路径识别与切换代码

(五)灯光与声音提示代码

(六)等停功能代码

五、代码调试与优化

(一)常见问题及解决方法

(二)优化策略与效果

六、总结与展望


一、电赛 C 题初印象

在 2022 年的电子设计大赛中,C 题 “小车跟随行驶系统” 成功吸引了众多电子设计爱好者的目光。这个题目要求设计一套由一辆领头小车和一辆跟随小车组成的系统,光是听起来就充满了挑战与趣味。

想象一下,两辆小车在特定的场地中行驶,一辆在前 “领航”,另一辆紧紧跟随,如同默契十足的伙伴。行驶场地的路径设计颇为巧妙,包含内圈和外圈 。内圈是 ABFDE 圆角矩形路径,外圈则是 ABCDE 圆角矩形路径。小车不仅要具备循迹功能,速度还得在 0.3 - 1m/s 之间灵活可调,以完成在指定路径上的行驶操作。当领头小车和跟随小车选择在内圈 BFD 段行驶时,还得发出灯光指示,仿佛在向外界宣告它们的位置。在测试过程中,还有个小 “彩蛋”,测试专家会在路径上 E 点所在边的直线区域放上 “等停指示” 标识,这时领头小车就得乖乖停车,等待 5 秒后再继续它的行程。而当小车完成一次行驶到达终点时,领头小车和跟随小车还要发出声音提示,就像是在欢呼自己完成了任务。这样的题目设定,既考验了硬件设计的能力,又对软件编程提出了很高的要求,也难怪能引发大家的热烈讨论和积极参与。

二、题目深度剖析

(一)功能要求拆解

  1. 小车循迹:小车需要精准识别并沿着指定的内圈 ABFDE 圆角矩形路径和外圈 ABCDE 圆角矩形路径行驶。这就如同我们开车时要时刻留意道路标识和车道线,不能偏离。循迹功能的实现依赖于传感器对路径的检测,要求传感器能够稳定地获取路径信息,并将其准确传输给小车的控制系统,就像我们的眼睛把道路信息传递给大脑一样。
  1. 速度调节:速度在 0.3 - 1m/s 之间可灵活调节,这对小车的动力系统和控制系统提出了较高要求。不同的行驶路径和任务可能需要不同的速度,比如在直线行驶时可以适当提高速度,而在转弯处则需要降低速度,以确保行驶的稳定性和准确性。这类似于汽车在高速公路和城市道路上行驶时,根据路况调整车速。
  1. 路径选择:虽然题目中没有明确给出路径选择的具体条件,但在实际操作中,可能需要根据一些外部因素或者预设的程序来决定小车是在内圈还是外圈行驶。这需要小车具备一定的智能决策能力,就像我们在选择出行路线时,会考虑交通状况、距离等因素。
  1. 灯光及声音提示:当领头小车和跟随小车选择在内圈 BFD 段行驶时,发出灯光指示,这是一种可视化的提示方式,方便观察小车的行驶状态和位置。而当小车完成一次行驶到达终点时,发出声音提示,就像是在告诉大家 “我完成任务啦”。这两种提示方式,一个通过视觉,一个通过听觉,为小车的行驶增加了更多的可观测性。
  1. 等停指示:当测试专家在路径上 E 点所在边的直线区域放上 “等停指示” 标识时,领头小车要停车等待 5 秒后再继续行驶。这要求小车的控制系统能够准确识别这个标识,并做出相应的停车和启动动作,对系统的响应速度和准确性有较高要求。

(二)技术难点分析

  1. 硬件方面
    • 传感器精度:循迹功能依赖的传感器精度至关重要。如果传感器精度不够,可能会导致小车误判路径,出现偏离轨道的情况。例如,常见的红外传感器可能会受到环境光线的干扰,影响其对路径黑线的检测精度;而摄像头传感器虽然能够获取更丰富的图像信息,但对图像的处理和分析要求较高,且成本也相对较高。
    • 电机控制:要实现速度在 0.3 - 1m/s 之间的精确调节,电机的控制就显得尤为关键。电机的转速会受到电压、负载等因素的影响,如何保证在不同的行驶条件下,电机都能稳定地输出所需的转速,是需要解决的问题。比如,在小车转弯时,由于离心力的作用,电机的负载会发生变化,这时就需要控制系统能够及时调整电机的输出,以保持稳定的速度。
  1. 软件方面
    • 信号处理:传感器采集到的信号需要进行有效的处理和分析,才能转化为小车控制系统能够理解的指令。在这个过程中,可能会遇到信号噪声、干扰等问题,如何对信号进行滤波、放大等处理,以提高信号的质量和准确性,是软件设计的难点之一。例如,对于红外传感器采集到的模拟信号,需要通过 A/D 转换将其转化为数字信号,然后再进行数字滤波处理,去除噪声干扰。
    • 控制算法:为了实现小车的稳定行驶和各种功能,需要设计合适的控制算法。比如,在循迹过程中,可以采用 PID 控制算法,通过对小车当前位置与目标路径的偏差进行计算,调整电机的转速和转向,使小车能够沿着路径准确行驶。但 PID 参数的整定是一个复杂的过程,需要根据实际情况进行多次调试和优化,才能达到最佳的控制效果。同时,在路径选择和等停指示等功能中,也需要设计相应的逻辑算法,以确保小车能够正确响应各种指令。

三、硬件基础搭建

(一)小车选型要点

在选择小车时,底盘结构和电机性能是两个关键要点。对于底盘结构,四轮差速底盘是一个不错的选择。这种底盘的优点在于它能够实现灵活的转向,就像汽车中的四轮驱动系统,在行驶过程中,通过调整四个轮子的转速差,可以轻松实现转弯、原地旋转等动作,这对于在复杂路径上行驶的小车来说至关重要。比如在完成内圈和外圈的圆角矩形路径行驶时,四轮差速底盘能够更好地适应弯道,保持稳定的行驶姿态。

而在电机性能方面,直流减速电机较为合适。它具有较大的扭矩,可以为小车提供足够的动力,确保小车在不同的路况下都能正常行驶。比如在遇到一些轻微的坡度或者摩擦力较大的地面时,直流减速电机也能稳定输出动力,使小车顺利通过。同时,它的转速可以通过 PWM(脉冲宽度调制)信号进行精确控制,这就为实现小车速度在 0.3 - 1m/s 之间的调节提供了便利。通过改变 PWM 信号的占空比,就可以轻松调整电机的转速,进而控制小车的行驶速度,满足题目中对速度调节的要求。

(二)传感器布局与原理

  1. 循迹传感器:循迹传感器通常采用红外对管的形式,安装在小车底盘的前端底部。其工作原理基于红外线的反射特性。当红外发射管发射出红外线时,如果下方是白色的地面,红外线会被大量反射回来,被红外接收管接收,此时接收管输出低电平信号;而当下方是黑色的路径线时,红外线会被吸收,反射回来的红外线很少,接收管输出高电平信号。通过多个红外对管组成的阵列,就可以获取小车相对于路径线的位置信息。比如,当中间的红外对管检测到高电平时,说明小车正处于路径线上;当左边的红外对管检测到高电平时,说明小车偏右了,需要向左调整方向,反之亦然。
  1. 速度传感器:速度传感器一般采用编码器的形式,安装在电机的转轴上。它的工作原理是通过记录电机转轴的旋转次数来计算小车的速度。编码器上有均匀分布的码盘,当电机转动时,码盘也随之转动,码盘上的缝隙会遮挡或允许光线通过,光线被遮挡或通过时,会产生脉冲信号。通过计算单位时间内的脉冲数量,就可以得出电机的转速,再结合车轮的半径等参数,就能计算出小车的行驶速度。例如,如果在 1 秒钟内检测到 100 个脉冲,已知码盘的每转脉冲数为 200,车轮半径为 5 厘米,那么就可以根据公式计算出小车的速度 。这种方式能够实时准确地获取小车的速度信息,为速度调节和控制提供依据。

四、软件代码核心实现

(一)整体代码架构设计

整体代码架构就像是一座大厦的蓝图,它决定了整个软件系统的布局和运行方式。在这个小车跟随行驶系统中,主程序就像是大厦的地基和框架,是整个系统的核心。它负责初始化各个硬件设备,就像为大厦搭建好基础结构,确保各个部分都能正常工作。然后,主程序进入一个无限循环,就像大厦里的各种活动永不停歇一样。在这个循环中,它不断调用各个功能模块,以实现小车的各种功能。

各功能模块之间有着紧密的调用关系。例如,循迹功能模块会实时采集循迹传感器的数据,就像人的眼睛不断观察周围环境一样,并将这些数据传递给路径识别与切换模块。路径识别与切换模块根据这些数据判断小车当前所在的路径,是内圈还是外圈,就像人根据周围的标识判断自己所处的位置一样。然后,它会将路径信息传递给速度控制模块和转向控制模块。速度控制模块根据路径信息和预设的速度要求,调整小车的速度,就像司机根据路况调整车速一样;转向控制模块则根据路径信息控制小车的转向,让小车能够沿着正确的路径行驶,就像司机根据道路方向转动方向盘一样。灯光与声音提示模块会根据小车的行驶状态,如是否在内圈 BFD 段行驶、是否到达终点等,控制灯光和声音的输出,就像交通信号灯和警报器根据交通状况发出指示一样。等停功能模块则会实时检测是否有等停指示,当检测到等停指示时,控制小车停车,并在等待 5 秒后重新启动,就像司机遇到红灯停车,绿灯亮起后再启动一样。

(二)循迹功能代码

 

// 假设使用三个红外循迹传感器,分别对应左、中、右

#define LEFT_SENSOR_PIN 2

#define MIDDLE_SENSOR_PIN 3

#define RIGHT_SENSOR_PIN 4

void setup() {

pinMode(LEFT_SENSOR_PIN, INPUT);

pinMode(MIDDLE_SENSOR_PIN, INPUT);

pinMode(RIGHT_SENSOR_PIN, INPUT);

}

void loop() {

int leftSensorValue = digitalRead(LEFT_SENSOR_PIN);

int middleSensorValue = digitalRead(MIDDLE_SENSOR_PIN);

int rightSensorValue = digitalRead(RIGHT_SENSOR_PIN);

if (middleSensorValue == HIGH) {

// 小车在路径上,保持直线行驶

straightDrive();

} else if (leftSensorValue == HIGH) {

// 小车偏右,向左调整方向

turnLeft();

} else if (rightSensorValue == HIGH) {

// 小车偏左,向右调整方向

turnRight();

}

}

void straightDrive() {

// 设置左右电机相同速度,实现直线行驶

analogWrite(LEFT_MOTOR_PIN, MOTOR_SPEED);

analogWrite(RIGHT_MOTOR_PIN, MOTOR_SPEED);

}

void turnLeft() {

// 左电机速度降低,右电机速度不变,实现向左转弯

analogWrite(LEFT_MOTOR_PIN, MOTOR_SPEED * 0.5);

analogWrite(RIGHT_MOTOR_PIN, MOTOR_SPEED);

}

void turnRight() {

// 右电机速度降低,左电机速度不变,实现向右转弯

analogWrite(LEFT_MOTOR_PIN, MOTOR_SPEED);

analogWrite(RIGHT_MOTOR_PIN, MOTOR_SPEED * 0.5);

}

在这段代码中,首先通过setup函数设置三个红外循迹传感器引脚为输入模式。在loop函数中,不断读取三个传感器的值。当中间传感器检测到高电平时,说明小车在路径上,调用straightDrive函数,让左右电机以相同速度运行,实现直线行驶;当左边传感器检测到高电平时,说明小车偏右,调用turnLeft函数,降低左电机速度,使小车向左调整方向;当右边传感器检测到高电平时,说明小车偏左,调用turnRight函数,降低右电机速度,使小车向右调整方向。通过这样的方式,小车就能根据传感器数据准确地沿着路径行驶。

(三)速度控制代码

在速度控制中,PID 控制算法是一种常用且有效的方法。PID 控制算法通过比例(P)、积分(I)、微分(D)三个参数来对系统进行控制。以下是使用 C 语言实现速度 PID 控制的代码示例:

 

// PID控制器参数

#define Kp 0.5

#define Ki 0.1

#define Kd 0.2

// 定义全局变量

double error = 0; // 误差

double integral = 0; // 积分项

double previous_error = 0; // 上一次的误差

double target_speed = 0.5; // 目标速度,单位m/s

double current_speed = 0; // 当前速度,单位m/s

// 速度读取函数,模拟从速度传感器获取速度

double readSpeedSensor() {

// 这里可以根据实际的速度传感器接口进行编写,暂时模拟返回一个值

return current_speed;

}

// PID控制函数

double pidControl(double setpoint, double feedback) {

error = setpoint - feedback;

integral += error;

double derivative = error - previous_error;

double output = Kp * error + Ki * integral + Kd * derivative;

previous_error = error;

return output;

}

void loop() {

current_speed = readSpeedSensor();

double control_signal = pidControl(target_speed, current_speed);

// 根据控制信号调整电机的PWM占空比,以控制速度

// 这里假设电机控制函数为setMotorPWM,根据实际情况编写

setMotorPWM(control_signal);

}

在这段代码中,首先定义了 PID 控制器的三个参数Kp、Ki、Kd,以及误差、积分项、上一次误差、目标速度和当前速度等全局变量。readSpeedSensor函数用于模拟从速度传感器读取当前速度。pidControl函数是 PID 控制的核心,它根据目标速度和当前速度计算出误差,然后分别计算积分项和微分项,最后根据比例、积分、微分三个参数计算出控制信号。在loop函数中,不断读取当前速度,调用pidControl函数计算控制信号,并根据控制信号调整电机的 PWM 占空比,从而实现对小车速度的精确控制。通过调整Kp、Ki、Kd这三个参数的值,可以使 PID 控制器更好地适应不同的系统特性和控制要求,达到更稳定、准确的速度控制效果。

(四)路径识别与切换代码

 

// 假设内圈和外圈路径的识别通过循迹传感器的不同组合状态来判断

// 例如,内圈路径的特定传感器组合为101,外圈路径为111

#define LEFT_SENSOR_PIN 2

#define MIDDLE_SENSOR_PIN 3

#define RIGHT_SENSOR_PIN 4

void setup() {

pinMode(LEFT_SENSOR_PIN, INPUT);

pinMode(MIDDLE_SENSOR_PIN, INPUT);

pinMode(RIGHT_SENSOR_PIN, INPUT);

}

void loop() {

int leftSensorValue = digitalRead(LEFT_SENSOR_PIN);

int middleSensorValue = digitalRead(MIDDLE_SENSOR_PIN);

int rightSensorValue = digitalRead(RIGHT_SENSOR_PIN);

int sensorCombination = (leftSensorValue << 2) | (middleSensorValue << 1) | rightSensorValue;

if (sensorCombination == 0b101) {

// 识别为内圈路径

path = INNER_PATH;

} else if (sensorCombination == 0b111) {

// 识别为外圈路径

path = OUTER_PATH;

}

// 根据识别的路径进行相应操作,例如调整速度、转向等

if (path == INNER_PATH) {

// 内圈路径的速度和转向设置

setSpeed(INNER_PATH_SPEED);

adjustSteering(INNER_PATH_STEERING);

} else if (path == OUTER_PATH) {

// 外圈路径的速度和转向设置

setSpeed(OUTER_PATH_SPEED);

adjustSteering(OUTER_PATH_STEERING);

}

}

在这段代码中,通过setup函数设置循迹传感器引脚为输入模式。在loop函数中,读取三个传感器的值,并将它们组合成一个三位二进制数sensorCombination。根据sensorCombination的值来判断小车当前所在的路径,如果是0b101,则识别为内圈路径;如果是0b111,则识别为外圈路径。识别出路径后,根据不同的路径设置相应的速度和转向参数,实现路径的切换和行驶控制。这样,小车就能根据路径的变化自动调整行驶状态,准确地在不同路径上行驶。

(五)灯光与声音提示代码

 

// 假设灯光连接到LED_PIN引脚,声音提示连接到BUZZER_PIN引脚

#define LED_PIN 5

#define BUZZER_PIN 6

void setup() {

pinMode(LED_PIN, OUTPUT);

pinMode(BUZZER_PIN, OUTPUT);

}

void loop() {

// 假设path为当前路径变量,取值为INNER_PATH或OUTER_PATH

if (path == INNER_PATH) {

// 在内圈路径行驶,判断是否在BFD段

if (isInBFDSection()) {

// 点亮灯光

digitalWrite(LED_PIN, HIGH);

} else {

digitalWrite(LED_PIN, LOW);

}

} else {

digitalWrite(LED_PIN, LOW);

}

// 假设isAtEnd为判断是否到达终点的函数

if (isAtEnd()) {

// 发出声音提示

tone(BUZZER_PIN, 1000, 1000); // 发出1000Hz频率的声音,持续1000ms

}

}

// 模拟判断是否在内圈BFD段的函数

bool isInBFDSection() {

// 这里可以根据实际的位置检测逻辑编写,暂时返回一个模拟值

return true;

}

// 模拟判断是否到达终点的函数

bool isAtEnd() {

// 这里可以根据实际的终点检测逻辑编写,暂时返回一个模拟值

return true;

}

在这段代码中,通过setup函数将灯光和声音提示的引脚设置为输出模式。在loop函数中,首先根据当前路径判断是否在内圈路径行驶,如果在内圈路径,再判断是否在 BFD 段,如果在 BFD 段,则点亮灯光,否则关闭灯光。当判断小车到达终点时,调用tone函数使蜂鸣器发出 1000Hz 频率的声音,持续 1000ms,实现声音提示功能。通过这样的代码逻辑,小车能够在特定的行驶状态下准确地给出灯光和声音提示,方便观察和判断小车的运行情况。

(六)等停功能代码

 

// 假设等停指示检测传感器连接到STOP_INDICATOR_PIN引脚

#define STOP_INDICATOR_PIN 7

void setup() {

pinMode(STOP_INDICATOR_PIN, INPUT);

}

void loop() {

int stopIndicatorValue = digitalRead(STOP_INDICATOR_PIN);

if (stopIndicatorValue == HIGH) {

// 检测到等停指示,停车

stopCar();

delay(5000); // 等待5秒

// 重新启动

startCar();

} else {

// 正常行驶

normalDrive();

}

}

void stopCar() {

// 设置左右电机速度为0,实现停车

analogWrite(LEFT_MOTOR_PIN, 0);

analogWrite(RIGHT_MOTOR_PIN, 0);

}

void startCar() {

// 设置左右电机为初始速度,重新启动

analogWrite(LEFT_MOTOR_PIN, INITIAL_MOTOR_SPEED);

analogWrite(RIGHT_MOTOR_PIN, INITIAL_MOTOR_SPEED);

}

void normalDrive() {

// 正常行驶的速度和转向控制

setSpeed(NORMAL_SPEED);

adjustSteering(NORMAL_STEERING);

}

在这段代码中,通过setup函数将等停指示检测传感器的引脚设置为输入模式。在loop函数中,不断读取等停指示检测传感器的值,如果检测到高电平,说明检测到等停指示,调用stopCar函数使小车停车,然后通过delay函数等待 5 秒,再调用startCar函数重新启动小车;如果没有检测到等停指示,则调用normalDrive函数使小车正常行驶。通过这样的代码实现,小车能够准确地响应等停指示,完成停车和重新启动的操作,满足题目中的等停功能要求。

五、代码调试与优化

(一)常见问题及解决方法

在代码调试过程中,我们常常会遇到各种令人头疼的问题,需要冷静分析并找到解决办法。

传感器数据异常是一个较为常见的问题。有时候,循迹传感器明明对着路径线,却输出了错误的信号,导致小车偏离路径。这可能是由于传感器受到了外界光线的干扰,比如在强光照射下,红外循迹传感器的检测精度就会受到影响 。解决这个问题,可以给传感器加上遮光罩,就像给我们的眼睛戴上墨镜一样,减少外界光线的干扰。或者对传感器采集到的数据进行滤波处理,去除噪声信号,提高数据的准确性。比如采用中值滤波算法,连续采集多次传感器数据,然后取中间值作为最终的有效数据,这样可以有效减少偶然因素导致的异常数据。

小车行驶不稳定也是一个困扰大家的难题。小车可能会在行驶过程中突然抖动、转向不灵活或者速度忽快忽慢。这可能是电机控制出现了问题,比如电机的驱动电压不稳定,或者电机的轴与轮子之间的连接松动。如果是驱动电压不稳定,可以检查电源电路,看看是否有电容漏电、稳压芯片工作异常等情况,确保提供给电机的电压稳定在合适的范围内。要是电机轴与轮子连接松动,就需要重新紧固连接部件,保证动力能够稳定地传输到轮子上,让小车平稳行驶。

(二)优化策略与效果

对代码进行优化是提升系统性能的关键步骤。在提高代码执行效率方面,可以从多个角度入手。比如在循环结构中,尽量减少不必要的计算。在之前给出的速度控制代码中,如果每次循环都重新计算一些固定的参数,就会浪费大量的计算资源。我们可以将这些固定参数的计算放在循环外部,只在程序初始化时计算一次,这样每次循环时就可以直接使用已经计算好的结果,大大提高了代码的执行速度。就好像我们每天上班,如果每天都要重新规划路线,会花费很多时间,而如果提前规划好固定的路线,每天直接按照这个路线走,就能节省时间。

在降低资源占用方面,合理使用内存是一个重要的优化点。在定义变量时,要根据实际需求选择合适的数据类型。如果一个变量只需要表示 0 到 100 之间的整数,却定义为占用较大内存空间的浮点数类型,就会造成内存的浪费。我们应该选择占用内存较小的整数类型,如uint8_t(无符号 8 位整数,取值范围 0 - 255),这样可以在满足需求的同时,减少内存的占用。另外,及时释放不再使用的内存资源也很重要。比如在动态分配内存时,使用完后要及时调用释放内存的函数,避免内存泄漏,就像我们用完房间后要及时退房,把资源腾出来给其他需要的人。

经过这些优化策略的实施,系统的性能得到了显著提升。小车的行驶更加稳定、流畅,响应速度也更快了。在相同的硬件条件下,优化后的代码能够让小车在规定路径上行驶的时间更短,完成任务的效率更高,这充分体现了代码优化的重要性和实际效果。

六、总结与展望

回顾 2022 电子设计大赛 C 题 “小车跟随行驶系统”,我们从对题目的初步印象,到深入剖析其功能要求和技术难点,再到一步步搭建硬件基础、实现软件代码核心功能,最后对代码进行调试与优化,这一路充满了挑战与收获。通过合理选择小车、精心布局传感器,我们为整个系统搭建了坚实的硬件基础;而在软件代码实现方面,通过巧妙设计整体架构,编写循迹、速度控制、路径识别与切换、灯光与声音提示以及等停功能等代码,让小车能够按照我们的预期在指定路径上稳定行驶,完成各种任务。

电子设计大赛是提升电子设计能力的绝佳舞台。它不仅考验我们对知识的掌握程度,更锻炼我们解决实际问题的能力、团队协作能力以及创新思维。希望更多的电子设计爱好者能够积极参与到电赛中来,在这个充满挑战与机遇的舞台上,不断提升自己的电子设计能力,创造出更多优秀的作品。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大雨淅淅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值