【屠龙勇士】BIT睿信书院屠龙勇士心得分享

【屠龙勇士】BIT睿信书院屠龙勇士心得分享

今天上午完成了本年度的屠龙比赛,由于本队开发和搭建任务由我全栈完成,故可将代码和心得完全公开给大家。如果科协的某位大大发现本文,也可以作为一个指导文章或者基础程序。考虑到学习压力时间不足,博文和代码都尽显草莽之色,但作为一个基础的指引,能够大大降低入门门槛。
该项目的Github传送门~

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. 小车三维照片~~

  • 上视图
    在这里插入图片描述

  • 前视图
    在这里插入图片描述

  • 右视图
    在这里插入图片描述

  • 后视图
    在这里插入图片描述

  • 左视图
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值