Arduino机器人While循环故障:传感器读取异常陷入死循环
问题分析与解决方案
看起来你遇到的核心问题是while循环内部没有重新读取传感器数据——一旦进入循环,inches3和inches2的值就停留在进入循环前的那次读数,只要初始条件满足(inches3 <=8 && inches2 <=12),循环就会一直执行下去,永远不会退出,自然也不会回到loop()开头重新读取传感器。
具体问题点
- 你的传感器读数逻辑只在
loop()的开头执行了一次,进入while循环后完全没有更新这些变量,判断条件永远不会改变; - 另外
pulseIn()函数默认超时时间是1秒,如果传感器没有检测到回波,会阻塞程序很久,可能影响实时性。
修改后的代码方案
我们需要把传感器读数的逻辑放到while循环内部,确保每次循环都能获取最新的传感器数据,同时可以给pulseIn()加上超时参数避免阻塞:
#include<SoftwareSerial.h> // Import the serial Library #include <Wire.h> #include <Adafruit_MotorShield.h> #include "utility/Adafruit_MS_PWMServoDriver.h" // Create the motor shield object with the default I2C address Adafruit_MotorShield AFMS = Adafruit_MotorShield(); // Select which 'port' M1, M2, M3 or M4. In this case, M1 Adafruit_DCMotor *FL= AFMS.getMotor(1); //Front left motor Adafruit_DCMotor *FR= AFMS.getMotor(4); //Front right motor int left_trig = 8; int left_echo = 9; int mid_trig = 5; int mid_echo = 6; int right_trig = 3; int right_echo = 4; long duration1, duration2, duration3, inches1, inches2, inches3; // 定义pulseIn的超时时间(单位:微秒),避免长时间阻塞 const long PULSE_TIMEOUT = 20000; // 20ms超时 void setup() { Serial.begin(9600); AFMS.begin(); // create with the default frequency 1.6KHz //This establishes the sensors as inputs and outputs pinMode(left_trig,OUTPUT); pinMode(left_echo,INPUT); pinMode (mid_trig,OUTPUT); pinMode(mid_echo,INPUT); pinMode (right_trig,OUTPUT); pinMode(right_echo,INPUT); FL->setSpeed(150); FL->run(FORWARD); FR->setSpeed(150); FR->run(BACKWARD); } // 封装传感器读数的函数,方便重复调用 void readSensors() { // 读取左侧传感器 digitalWrite(left_trig, LOW); delayMicroseconds(2); digitalWrite(left_trig, HIGH); delayMicroseconds(10); duration1 = pulseIn(left_echo, HIGH, PULSE_TIMEOUT); // 加入超时 // 读取中间传感器 digitalWrite(mid_trig, LOW); delayMicroseconds(2); digitalWrite(mid_trig, HIGH); delayMicroseconds(10); duration2 = pulseIn(mid_echo, HIGH, PULSE_TIMEOUT); // 读取右侧传感器 digitalWrite(right_trig, LOW); delayMicroseconds(2); digitalWrite(right_trig, HIGH); delayMicroseconds(10); duration3 = pulseIn(right_echo, HIGH, PULSE_TIMEOUT); // 转换为英寸 inches1 = microsecondsToInches(duration1); inches2 = microsecondsToInches(duration2); inches3 = microsecondsToInches(duration3); } void loop() { // 先读取一次传感器,获取初始状态 readSensors(); // 打印传感器数据 Serial.print(inches1); Serial.print("in, "); Serial.print(inches2); Serial.print("in, "); Serial.print(inches3); Serial.print("in"); Serial.println(); // 检查是否需要进入转向循环 while(inches3 <=8 && inches2 <=12){ // 关键:在循环内部重新读取传感器! readSensors(); // 可以在循环内打印调试数据 Serial.print("[转向中] "); Serial.print(inches1); Serial.print("win, "); Serial.print(inches2); Serial.print("win, "); Serial.print(inches3); Serial.print("win"); Serial.println(); // 执行转向动作 FL->setSpeed(120); FL->run(BACKWARD); FR->setSpeed(120); FR->run(BACKWARD); // 加个短延迟,避免过于频繁读取传感器(可选,根据实际情况调整) delay(20); } // 转向完成,恢复正常行驶 FL->setSpeed(150); FL->run(FORWARD); FR->setSpeed(150); FR->run(BACKWARD); delay(50); } long microsecondsToInches(long microseconds) { // 处理超时返回0的情况,避免计算出负数或异常值 if(microseconds == 0) return 999; // 用一个大值表示无检测 return microseconds / 74 / 2; }
关键修改说明
- 把传感器读数逻辑封装成
readSensors()函数,方便在loop()和while循环内重复调用; - 在while循环内部必须调用
readSensors(),实时更新inches3和inches2的值,这样当传感器检测到满足退出条件时,循环会自动结束; - 给
pulseIn()添加了超时参数,避免传感器无回波时程序长时间阻塞; - 在
microsecondsToInches()里处理了超时返回0的情况,避免出现异常的距离值; - 增加了转向过程中的调试打印,方便你观察传感器数据变化。
这样修改后,机器人会在满足转向条件时进入while循环执行转向,同时持续检测传感器,一旦条件不满足就退出循环,恢复正常行驶。
内容的提问来源于stack exchange,提问作者Deon Hargrove




