【屠龙勇士】BIT睿信书院屠龙勇士心得分享
今天上午完成了本年度的屠龙比赛,由于本队开发和搭建任务由我全栈完成,故可将代码和心得完全公开给大家。如果科协的某位大大发现本文,也可以作为一个指导文章或者基础程序。考虑到学习压力时间不足,博文和代码都尽显草莽之色,但作为一个基础的指引,能够大大降低入门门槛。
该项目的Github传送门~
- Github 链接DragonSlay-BIT
- Gitcode镜像Gitcode镜像
屠龙心得
- 【屠龙勇士】BIT睿信书院屠龙勇士心得分享
- 1. 关卡说明
- 1.1 关卡1:自动循迹
- 1.2 关卡2:超声波避障
- 1.3 关卡3:屠龙勇士
- 2. 接线指导与测试代码
- 2.1 电压测试器
- 1.2 L298N 电机驱动模块
- 1.2.2 电机驱动测试代码
- 1.3 HC-SR04 雷达模块
- 1.3.2 雷达测试代码
- 1.4 六路红外循迹
- 1.4.2 红外测试代码
- 1.5 SG90 舵机
- 1.5.2 舵机测试代码
- 1.6 蓝牙
- 1.6.2 蓝牙测试代码
- 1.7 整体布局图(高清图请前往Repo取)
- 3. 调参心得
- 4. 寄语
- 5. 小车三维照片~~
1. 关卡说明
1.1 关卡1:自动循迹
- 包括直线、锐角弯、钝角弯、S弯、斜坡;通过斜坡可额外加5分
- 禁止以非红外巡线的方式完成此关卡
1.2 关卡2:超声波避障
- 包括狭长通道、多个转弯
- 终点前设有粗黑色横线,若小车行驶至该横线处自动停下,则额外加5分
1.3 关卡3:屠龙勇士
- 出口1无守卫龙,出口2设有守卫龙,每撞倒一条龙得5分
- 使用泡沫球射击守卫龙。每辆小车共有6次射击机会;
-
- 若不使用舵机控制,手动放置小球,每击中一条守卫龙得5分
-
- 通过舵机控制泡沫球自动装填并发射命中守卫龙则得10分,多次命中同一条龙不重复得分
2. 接线指导与测试代码
该内容如果与Repo下./分模块组装/布局图.drawio
有任何冲突,应当优先考虑布局图的接线方案。
2.1 电压测试器
直接插到航模电池的充电口(即单只电池口);有金属片的一面向上
- 插入后将会响一声(特别洪亮)
- 然后显示总电压、分电压(用的3s就显示三个的分别电压)
- 按住喇叭后面的微动按钮,可以调整报警值;若电池低于报警值,蜂鸣器和红灯将会报警
1.2 L298N 电机驱动模块
由于本文主要服务于比赛,就不额外讲这个模块的可选配置了,直接按照我的方案来做就好。
这个接线在接线柱放到最松的时候,可以直接怼进去(可以适度用钳子压扁);再拧紧,防止虚接(徐姐发热)
一下是接线图,除了电池正负极外,不需要纠结电机的正负极,这个到时候直接调整代码即可。
这个时候参考布局图.draw
接线;在测试代码里面选择电机驱动代码进行测试
1.2.2 电机驱动测试代码
// Ardunio + L298n;使用analogWrite以控制输出电平
// in1 - in4 分别接到 5、6、9、10
// 完成高速、低速;前后左右转;每一轮3s;将当轮情况输出到终端
// 定义电机控制引脚
#define IN1 5
#define IN2 6
#define IN3 3
#define IN4 11// 定义速度等级
#define HIGH_SPEED 200 // 高速 (PWM值 0-255)
#define LOW_SPEED 80 // 低速void setup()
{// 设置电机控制引脚为输出pinMode(IN1, OUTPUT);pinMode(IN2, OUTPUT);pinMode(IN3, OUTPUT);pinMode(IN4, OUTPUT);// 初始化串口通信Serial.begin(9600);Serial.println("L298N Motor Control Demo");
}void loop()
{// 高速前进(两个电机正转)motorControl(HIGH_SPEED, HIGH_SPEED);Serial.println("高速前进");delay(3000);// 低速前进motorControl(LOW_SPEED, LOW_SPEED);Serial.println("低速前进");delay(3000);// 高速后退(两个电机反转)motorControl(-HIGH_SPEED, -HIGH_SPEED);Serial.println("高速后退");delay(3000);// 低速后退motorControl(-LOW_SPEED, -LOW_SPEED);Serial.println("低速后退");delay(3000);// 左转(左轮后退,右轮前进)motorControl(-HIGH_SPEED, HIGH_SPEED);Serial.println("高速左转");delay(3000);// 低速左转motorControl(-LOW_SPEED, LOW_SPEED);Serial.println("低速左转");delay(3000);// 右转(左轮前进,右轮后退)motorControl(HIGH_SPEED, -HIGH_SPEED);Serial.println("高速右转");delay(3000);// 低速右转motorControl(LOW_SPEED, -LOW_SPEED);Serial.println("低速右转");delay(3000);// 停止motorControl(0, 0);Serial.println("停止");delay(2000);delay(20000);
}// 电机控制函数(修正版)
// 参数:左轮速度,右轮速度(范围-255~255,负值表示反转)
void motorControl(int leftSpeed, int rightSpeed)
{// 限制速度范围leftSpeed = constrain(leftSpeed, -255, 255);rightSpeed = constrain(rightSpeed, -255, 255);// constrain(x, a, b)/*x:要限制的值(可以是整数或浮点数)a:范围下限(最小值)b:范围上限(最大值) */// 控制左轮(IN1/IN2)if (leftSpeed > 0){analogWrite(IN1, leftSpeed);analogWrite(IN2, 0);}else if (leftSpeed < 0){analogWrite(IN1, 0);analogWrite(IN2, -leftSpeed);}else{digitalWrite(IN1, LOW);digitalWrite(IN2, LOW);}// 控制右轮(IN3/IN4)if (rightSpeed > 0){analogWrite(IN3, rightSpeed);analogWrite(IN4, 0);}else if (rightSpeed < 0){analogWrite(IN3, 0);analogWrite(IN4, -rightSpeed);}else{digitalWrite(IN3, LOW);digitalWrite(IN4, LOW);}
}
1.3 HC-SR04 雷达模块
逐个插进去,如图。所有的T端口插在面包板上进行汇流(少了材料记得找组织方补充)
这个时候参考布局图.draw
接线;在测试代码里面选择雷达代码进行测试
1.3.2 雷达测试代码
// 使用Arduino+sr04 进行雷达测距
// 一共有三组雷达,分别是左3前2右1;端口为2-TG1;3-TG2;4-TG3;8-EC1;12-EC2;13 - EC3
// 定义超声波模块引脚const int trigPinLeft = 4;
const int trigPinFront = 7;
const int trigPinRight = 2;const int echoPinLeft = 13;
const int echoPinFront = 12;
const int echoPinRight = 8;void setup() {Serial.begin(9600); // 初始化串口通信// 设置引脚模式pinMode(trigPinLeft, OUTPUT);pinMode(echoPinLeft, INPUT);pinMode(trigPinFront, OUTPUT);pinMode(echoPinFront, INPUT);pinMode(trigPinRight, OUTPUT);pinMode(echoPinRight, INPUT);Serial.println("三向超声波雷达测距系统已启动");
}void loop() {// 测量三个方向的距离float distanceLeft = getDistance(trigPinLeft, echoPinLeft);float distanceFront = getDistance(trigPinFront, echoPinFront);float distanceRight = getDistance(trigPinRight, echoPinRight);// 打印测量结果Serial.print("左侧距离: ");Serial.print(distanceLeft);Serial.print(" cm | 前方距离: ");Serial.print(distanceFront);Serial.print(" cm | 右侧距离: ");Serial.print(distanceRight);Serial.println(" cm");delay(200); // 适当延时
}// 超声波测距函数
float getDistance(int trigPin, int echoPin) {digitalWrite(trigPin, LOW);delayMicroseconds(2);digitalWrite(trigPin, HIGH);delayMicroseconds(10);digitalWrite(trigPin, LOW);long duration = pulseIn(echoPin, HIGH);float distance = duration * 0.034 / 2; // 计算距离(cm)// 过滤异常值if(distance > 400 || distance < 2) {distance = -1; // 表示超出测量范围}return distance;
}
1.4 六路红外循迹
这个时候参考布局图.draw
接线;在测试代码里面选择六路红外代码进行测试
1.4.2 红外测试代码
// 定义红外循迹模块引脚
#define IR_1 A0 // 红外模块1
#define IR_2 A1 // 红外模块2
#define IR_3 A2 // 红外模块3
#define IR_4 A3 // 红外模块4
#define IR_5 A4 // 红外模块5
#define IR_6 A5 // 红外模块6// 存储红外模块的检测值
int irValues[6]; // 用于存储6个红外模块的检测值void setup() {// 设置引脚模式pinMode(IR_1, INPUT);pinMode(IR_2, INPUT);pinMode(IR_3, INPUT);pinMode(IR_4, INPUT);pinMode(IR_5, INPUT);pinMode(IR_6, INPUT);// 初始化串口通信Serial.begin(9600);Serial.println("Six-channel IR line follower testing started...");
}void loop() {// 读取6个红外模块的值irValues[0] = digitalRead(IR_1);irValues[1] = digitalRead(IR_2);irValues[2] = digitalRead(IR_3);irValues[3] = digitalRead(IR_4);irValues[4] = digitalRead(IR_5);irValues[5] = digitalRead(IR_6);// 输出红外模块的检测值Serial.print("IR 1: ");Serial.print(irValues[0]);Serial.print(" | IR 2: ");Serial.print(irValues[1]);Serial.print(" | IR 3: ");Serial.print(irValues[2]);Serial.print(" | IR 4: ");Serial.print(irValues[3]);Serial.print(" | IR 5: ");Serial.print(irValues[4]);Serial.print(" | IR 6: ");Serial.println(irValues[5]);delay(200); // 每隔200毫秒检测一次
}
1.5 SG90 舵机
这个时候参考布局图.draw
接线;在测试代码里面选择舵机代码进行测试
1.5.2 舵机测试代码
#include <Servo.h> // 引入Servo库// 定义舵机引脚
#define SERVO_PIN 10// 创建舵机对象
Servo myServo;// 定义舵机初始角度
int angle = 0; // 初始角度为0度void setup() {// 将舵机连接到指定引脚myServo.attach(SERVO_PIN);// 初始化串口通信Serial.begin(9600);Serial.println("Servo control started...");
}void loop() {// 设置舵机角度myServo.write(angle); // 将舵机转动到指定角度// 输出当前角度Serial.print("Servo angle: ");Serial.println(angle);// 更新角度angle += 30; // 每次增加30度// 如果角度超过180度,重置为0度if (angle > 180) {angle = 0;}delay(1000); // 每隔1秒转动一次
}
1.6 蓝牙
参考布局图.draw
接线;不用单独测试。但是每次通过串口刷写数据的时候,必须断开蓝牙的上传和下载接线。因为串口线公用,接蓝牙会导致程序刷写失败。
1.6.2 蓝牙测试代码
void setup() {// 初始化硬件串口(用于与PC通信)Serial.begin(9600);// 初始化软件串口(用于与蓝牙模块通信)BTSerial.begin(9600);Serial.println("Bluetooth Test Started");
}void loop() {// 如果从蓝牙模块接收到数据,则将其打印到串口监视器if (BTSerial.available()) {char receivedChar = BTSerial.read();Serial.print("Received: ");Serial.println(receivedChar);}// 如果从串口监视器接收到数据,则将其发送到蓝牙模块if (Serial.available()) {char sendChar = Serial.read();BTSerial.write(sendChar);Serial.print("Sent: ");Serial.println(sendChar);}
}
1.7 整体布局图(高清图请前往Repo取)
3. 调参心得
- 能跑的代码就是好代码,走的再慢再丑,能完赛的就是好代码。大幅改代码一定要备份(可用git或用复制备份代码,做好批注)
- 电压影响:你的电池的电压的高低,可能会影响马达输出。如果你的代码健壮性不足,可能会早上调的好模型,到了晚上电池不足时,就会特别糟糕
- 轮胎影响:测试的时候可能会烧胎(尤其是超声波前期测试容易撞墙),烧胎后抓地力会受影响。同电压影响,这会让健壮性不足的模型有糟糕的表现
- 比赛策略:某些要求属于进阶要求(如锐角转弯、循迹爬坡、超声转弯决策),请谨慎考虑你的技术能力和赛场情况,优先保证你的模型的普适性(即当你认为你的代码已经足够好之前,反复从多个方向多个场景测试代码)。(例如我在赛前放弃了红外爬坡,一方面我动力调的比较小,二方面爬坡需要改红外的高度,要改结构的同时也对红外灵敏度有影响)(在赛中锐角失败,放弃了第二次尝试等等)
- 蓝牙:不知道是我的蓝牙软件的原因还是小车软件的原因,容易出现输入一个信息后,蓝牙软件卡死闪退……如果你发现了问题所在,可以在博文留言或者给Repo提交PR,感激不尽。
4. 寄语
最后最后,我希望队内最后至少有一个人,对小车的所有技术细节有基础的了解。这个感悟是我在赛前调参感悟的。这样的全能视角能帮助你在模拟赛道上快速调优,而不是像无头苍蝇一样乱试。
5. 小车三维照片~~
-
上视图
-
前视图
-
右视图
-
后视图
-
左视图