// 使用了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();
  }
}
