Files
mqtt_power/SR04_distance/SR04_distance.ino

250 lines
7.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 使用了SR04超声波传感器、TRCT5000循迹传感器、SG90舵机和直流电机进行循迹避障测试
// 逻辑: 第一次检测到障碍物后开始循迹,第二次检测到障碍物后停止。
#include <Servo.h>
// --- Pin Definitions ---
// Servo
Servo myServo;
const int servoPin = 9;
// Ultrasonic Sensor - Front (for start/stop control)
const int frontTrigPin = 2;
const int frontEchoPin = 3;
// Ultrasonic Sensor - Side (for pausing)
const int sideTrigPin = 8;
const int sideEchoPin = 6;
// LED Pin
const int ledPin = A2;
// Line Following Sensors
const int trct5000_02 = A1; // 左循迹传感器
const int trct5000_01 = A0; // 右循迹传感器
// Motor Control Pins (assuming L298N-like driver)
// Right Motor (User identified pin 5 as right motor)
const int ENA = 4; // 使能A
const int IN1 = 5; // 输入1 (速度)
const int IN2 = 10; // 输入2 (方向)
// Left Motor
const int ENB = 7; // 使能B
const int IN3 = 12; // 输入3 (速度)
const int IN4 = 11; // 输入4 (方向)
// --- Global Variables & Constants ---
float frontDistance;
float sideDistance;
const int OBSTACLE_THRESHOLD = 20; // 障碍物检测阈值 (cm)
int obstacleDetections = 0;
bool obstaclePreviouslySeen = false;
bool ignoreSideSensor = false; // 新增:用于在恢复后忽略侧方传感器
int sideObstacleCounter = 0; // 新增:用于过滤侧方传感器的抖动
int frontStopCounter = 0; // 新增:用于最终停止的防抖
// 定义状态机
enum State {
IDLE,
LINE_FOLLOWING,
PAUSED_BY_SIDE_OBSTACLE, // 新增:被侧方障碍物暂停的状态
STOPPED
};
State currentState = IDLE;
// --- Function Prototypes ---
void motorStop();
void motorForward(int speed);
void setup() {
Serial.begin(9600);
myServo.attach(servoPin, 500, 2500);
// 初始化超声波传感器引脚
pinMode(frontTrigPin, OUTPUT);
pinMode(frontEchoPin, INPUT);
pinMode(sideTrigPin, OUTPUT);
pinMode(sideEchoPin, INPUT);
// 初始化LED引脚
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH); // 初始为高电平,灯灭
// 初始化循迹传感器引脚
pinMode(trct5000_01, INPUT);
pinMode(trct5000_02, INPUT);
// 初始化电机控制引脚
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// 设置初始状态
motorStop();
myServo.write(90); // 舵机居中
Serial.println("System Initialized. State: IDLE");
Serial.println("Waiting 3 seconds for sensors to stabilize...");
delay(3000); // 增加延时以确保传感器稳定
}
void loop() {
// 1. 读取前方传感器 (用于主流程控制)
digitalWrite(frontTrigPin, LOW);
delayMicroseconds(2);
digitalWrite(frontTrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(frontTrigPin, LOW);
frontDistance = pulseIn(frontEchoPin, HIGH) / 58.00;
// 2. 状态机主要逻辑
switch (currentState) {
case IDLE:
motorStop();
Serial.println("State: IDLE");
// 检测前方障碍物以启动
if (frontDistance < OBSTACLE_THRESHOLD && frontDistance > 0 && !obstaclePreviouslySeen) {
obstacleDetections++;
Serial.print("Obstacle detected! Count: ");
Serial.println(obstacleDetections);
currentState = LINE_FOLLOWING;
Serial.println("State change -> LINE_FOLLOWING");
}
break;
case LINE_FOLLOWING:
// 检查前方障碍物以进入最终停止状态 (增加防抖逻辑)
if (frontDistance < OBSTACLE_THRESHOLD && frontDistance > 0) {
frontStopCounter++;
} else {
frontStopCounter = 0;
}
if (frontStopCounter >= 5) { // 要求连续5次检测到才触发最终停止
currentState = STOPPED;
Serial.println("State change -> STOPPED");
break; // 退出 switch 语句
}
// 检查侧方障碍物以进入暂停状态 (增加防抖逻辑)
if (!ignoreSideSensor) {
digitalWrite(sideTrigPin, LOW);
delayMicroseconds(2);
digitalWrite(sideTrigPin, HIGH);
delayMicroseconds(10);
digitalWrite(sideTrigPin, LOW);
sideDistance = pulseIn(sideEchoPin, HIGH) / 58.00;
if (sideDistance < OBSTACLE_THRESHOLD && sideDistance > 0) {
sideObstacleCounter++; // 如果检测到计数器加1
} else {
sideObstacleCounter = 0; // 如果没检测到,计数器清零
}
if (sideObstacleCounter >= 3) { // 要求连续3次检测到才触发暂停
currentState = PAUSED_BY_SIDE_OBSTACLE;
Serial.println("State change -> PAUSED_BY_SIDE_OBSTACLE");
sideObstacleCounter = 0; // 重置计数器
break;
}
}
// 执行循迹
motorForward(90); // 采用用户设定的速度
// 读取循迹传感器
bool leftOnLine = digitalRead(trct5000_02);
bool rightOnLine = digitalRead(trct5000_01);
// 使用舵机进行方向控制 (采用用户设定的角度)
if (leftOnLine && !rightOnLine) {
myServo.write(75);
} else if (!leftOnLine && rightOnLine) {
myServo.write(105);
}
break;
case PAUSED_BY_SIDE_OBSTACLE:
motorStop();
digitalWrite(ledPin, LOW); // 亮灯
Serial.println("State: PAUSED");
// 在暂停状态下,只检测前方障碍物以恢复运动
if (frontDistance < OBSTACLE_THRESHOLD && frontDistance > 0) {
digitalWrite(ledPin, HIGH); // 灭灯
ignoreSideSensor = true; // 设置标志位,永久忽略侧方传感器
currentState = LINE_FOLLOWING;
Serial.println("Resuming, ignoring side sensor from now on.");
// 为了防止这次检测被错误地计为第二次停止指令,短暂延时并重置检测标志
delay(200);
obstaclePreviouslySeen = true;
}
break;
case STOPPED:
motorStop();
break;
}
// 更新前方障碍物的检测标志位,用于识别"新"的障碍物事件
obstaclePreviouslySeen = (frontDistance < OBSTACLE_THRESHOLD && frontDistance > 0);
delay(10); // 采用用户设定的循环延时
}
// --- Motor Control Functions ---
// 电机停止 (根据L298N标准将输入引脚设为LOW实现刹车)
void motorStop() {
// 将方向控制引脚都设为LOW使电机刹车
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
// 为保险起见也将使能引脚的PWM输出设为0
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}
// 电机前进 (实现"kick-start"以在低速下启动)
void motorForward(int speed) {
// 定义电机启动阈值和"kick"参数
const int START_THRESHOLD = 140; // 电机启动的最小PWM值
const int KICK_SPEED = 180; // 用于克服惯性的瞬时启动速度
const int KICK_DURATION = 20; // 启动脉冲的持续时间 (ms)
// 1. 设置电机方向为前进 (根据用户最新配置)
// 右电机
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
// 左电机 (用户已反转)
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
// 2. 使用PWM在Enable引脚上设置速度, 对低速进行"kick-start"
if (speed > 0 && speed < START_THRESHOLD) {
// 先用一个较高的速度"kick"一下来克服静摩擦力
analogWrite(ENA, KICK_SPEED);
analogWrite(ENB, KICK_SPEED);
delay(KICK_DURATION);
// 然后迅速降低到目标低速来维持运动
analogWrite(ENA, speed);
analogWrite(ENB, speed);
} else if (speed >= START_THRESHOLD) {
// 对于高于阈值的速度,直接设置
analogWrite(ENA, speed);
analogWrite(ENB, speed);
} else { // speed == 0
// 如果目标速度为0则调用刹车函数
motorStop();
}
}