Files
mqtt_power/arduino_nano_tracker/arduino_nano_tracker.ino

184 lines
7.8 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.

#include <Servo.h> // 舵机库
// 引脚定义
// 电机
const int LEFT_MOTOR_PIN = 9; // 左电机PWM控制引脚
const int RIGHT_MOTOR_PIN = 10; // 右电机PWM控制引脚
// TRCT5000 循迹传感器
const int LEFT_TRCT_PIN = 7; // 左循迹传感器引脚
const int RIGHT_TRCT_PIN = 8; // 右循迹传感器引脚
// 超声波传感器
const int TRIG_PIN = 12; // 超声波Trig引脚
const int ECHO_PIN = 11; // 超声波Echo引脚
// 舵机
const int SERVO_PIN = 3; // 舵机控制引脚
Servo steeringServo; // 创建舵机对象
// 常量定义
const int OBSTACLE_DISTANCE_THRESHOLD_CM = 20; // 障碍物检测阈值 (厘米)
const int SERVO_NEUTRAL_ANGLE = 90; // 舵机中间位置角度
const int SERVO_LEFT_ANGLE = 75; // 舵机微调左转角度 (原为60, 调整为更小角度)
const int SERVO_RIGHT_ANGLE = 105; // 舵机微调右转角度 (原为120, 调整为更小角度)
// 电机速度 (analogWrite PWM值范围 0-255) - 这些常量在新的电机控制逻辑下意义减弱
const int MOTOR_STATE_STOP = LOW; // 电机停止状态 (使用LOW)
const int MOTOR_STATE_RUN = HIGH; // 电机运行状态 (使用HIGH)
// 保留旧的常量名以便于理解之前的逻辑但实际传递给电机控制函数的值会被转换为HIGH/LOW
const int MOTOR_SPEED_STOP = 0; // 逻辑上的停止 (会转换为LOW)
const int MOTOR_SPEED_NORMAL = 1; // 逻辑上的运行 (会转换为HIGH)
const int MOTOR_SPEED_SLOW = 1; // 逻辑上的运行 (会转换为HIGH)
const int MOTOR_SPEED_TURN_ASSIST = 1; // 逻辑上的运行 (会转换为HIGH)
// const int MOTOR_SPEED_DIFFERENTIAL_SLOW = 70; // 这个在单边驱动时不再直接使用
// TRCT5000 传感器逻辑 (假设检测到黑线为低电平, 白色地面为高电平)
// 具体根据你的传感器模块实际输出进行调整 (例如,如果模块输出反相,则需要调换定义)
#define ON_LINE LOW // 在线上 (检测到黑线)
#define OFF_LINE HIGH // 不在线上 (检测到白色地面)
void setup() {
// 初始化串口通信波特率9600
Serial.begin(9600);
while (!Serial) {
; // 等待串口连接 (对于某些板子如Leonardo是必需的Nano通常不需要但加上无害)
}
Serial.println("串口已连接。");
// 初始化电机引脚为输出模式
pinMode(LEFT_MOTOR_PIN, OUTPUT);
pinMode(RIGHT_MOTOR_PIN, OUTPUT);
// 初始化TRCT5000循迹传感器引脚为输入模式
pinMode(LEFT_TRCT_PIN, INPUT);
pinMode(RIGHT_TRCT_PIN, INPUT);
// 初始化超声波传感器引脚
pinMode(TRIG_PIN, OUTPUT); // Trig引脚为输出
pinMode(ECHO_PIN, INPUT); // Echo引脚为输入
// 舵机初始化连接到SERVO_PIN并设置到中间位置
steeringServo.attach(SERVO_PIN);
steeringServo.write(SERVO_NEUTRAL_ANGLE);
// 确保初始状态电机停止
stopMotors();
Serial.println("初始状态:电机已停止。");
Serial.println("Arduino Nano 循迹避障小车 初始化完成,准备就绪。");
Serial.println("-----------------------------------------");
}
void loop() {
Serial.println("--- 开始新循环 ---");
long distance = readUltrasonicDistance(); // 读取超声波测量的距离
Serial.print("超声波距离: "); Serial.print(distance); Serial.println(" cm");
if (distance > 0 && distance < OBSTACLE_DISTANCE_THRESHOLD_CM) {
// 如果检测到障碍物 (距离大于0且小于阈值)
Serial.println("状态更新:检测到障碍物! 执行停止。");
stopMotors(); // 停止电机
steeringServo.write(SERVO_NEUTRAL_ANGLE); // 舵机回中
Serial.println("动作:舵机回中。");
} else {
Serial.println("状态更新:无障碍物,执行循迹逻辑。");
trackLine();
}
Serial.println("--- 循环结束,延时 ---");
delay(100); // 稍微增加延时方便观察串口输出原为50
}
// --- 电机控制函数 ---
void controlMotors(int leftState, int rightState) {
// 直接使用digitalWrite控制电机HIGH为全速LOW为停止
// leftState 和 rightState 现在应该代表 MOTOR_STATE_RUN (HIGH) 或 MOTOR_STATE_STOP (LOW)
digitalWrite(LEFT_MOTOR_PIN, leftState);
digitalWrite(RIGHT_MOTOR_PIN, rightState);
Serial.print("电机控制(直接驱动):左轮状态=");
Serial.print(leftState == HIGH ? "运行(HIGH)" : "停止(LOW)");
Serial.print(", 右轮状态=");
Serial.println(rightState == HIGH ? "运行(HIGH)" : "停止(LOW)");
}
void moveForward() { // 不再需要speed参数因为总是全速
Serial.println("动作:向前行驶 (电机全速)。");
steeringServo.write(SERVO_NEUTRAL_ANGLE); // 确保舵机在中间位置 (直行)
Serial.println("动作:舵机回中 (配合直行)。");
controlMotors(MOTOR_STATE_RUN, MOTOR_STATE_RUN); // 设置左右电机运行
}
void stopMotors() {
Serial.println("动作:停止电机。");
controlMotors(MOTOR_STATE_STOP, MOTOR_STATE_STOP); // 设置左右电机停止
}
void turnLeft() { // 不再需要turnSpeed参数
Serial.println("动作:左转 (电机全速,舵机控制)。");
steeringServo.write(SERVO_LEFT_ANGLE); // 舵机打到左转角度
Serial.print("动作:舵机打到左转角度 ("); Serial.print(SERVO_LEFT_ANGLE); Serial.println("度)。");
// 两个电机都保持运行,转向仅靠舵机
controlMotors(MOTOR_STATE_RUN, MOTOR_STATE_RUN);
}
void turnRight() { // 不再需要turnSpeed参数
Serial.println("动作:右转 (电机全速,舵机控制)。");
steeringServo.write(SERVO_RIGHT_ANGLE); // 舵机打到右转角度
Serial.print("动作:舵机打到右转角度 ("); Serial.print(SERVO_RIGHT_ANGLE); Serial.println("度)。");
// 两个电机都保持运行,转向仅靠舵机
controlMotors(MOTOR_STATE_RUN, MOTOR_STATE_RUN);
}
// --- 传感器读取函数 ---
long readUltrasonicDistance() {
// 读取超声波传感器距离 (返回厘米cm)
// 清除TRIG_PIN的任何先前状态确保低电平
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
// 发送一个10微秒的高电平脉冲到TRIG_PIN以触发超声波发送
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// 读取ECHO_PIN返回的脉冲持续时间 (单位:微秒)
// pulseIn函数会等待引脚变为高电平然后开始计时再等待引脚变为低电平停止计时。
long duration = pulseIn(ECHO_PIN, HIGH);
// 计算距离 (单位:厘米)
// 声速 = 343米/秒 = 0.0343 厘米/微秒
// 距离 = (时间 * 声速) / 2 (因为声波是往返的)
long distance = duration * 0.0343 / 2;
// Serial.print("[内部] 超声波原始时长: "); Serial.println(duration);
return distance;
}
void trackLine() {
// 循迹逻辑
int leftSensorVal = digitalRead(LEFT_TRCT_PIN); // 读取左循迹传感器状态
int rightSensorVal = digitalRead(RIGHT_TRCT_PIN); // 读取右循迹传感器状态
Serial.print("循迹传感器状态: 左=");
Serial.print(leftSensorVal == ON_LINE ? "线上(LOW)" : "线下(HIGH)");
Serial.print(", 右=");
Serial.println(rightSensorVal == ON_LINE ? "线上(LOW)" : "线下(HIGH)");
// 新的循迹逻辑:默认前进,检测到线时微调方向 (电机始终全速)
if (leftSensorVal == ON_LINE && rightSensorVal == OFF_LINE) {
Serial.println("循迹判断:左线上,右线下 -> 执行左转 (电机保持运行)");
turnLeft();
} else if (leftSensorVal == OFF_LINE && rightSensorVal == ON_LINE) {
Serial.println("循迹判断:左线下,右线上 -> 执行右转 (电机保持运行)");
turnRight();
} else if (leftSensorVal == ON_LINE && rightSensorVal == ON_LINE) {
Serial.println("循迹判断:两侧均线上 -> 执行直行 (电机保持运行)");
moveForward(); // 两侧都压线,也直行
} else { // leftSensorVal == OFF_LINE && rightSensorVal == OFF_LINE
Serial.println("循迹判断:两侧均线下 -> 执行直行 (电机保持运行)");
moveForward();
}
}