You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Arduino机器人While循环故障:传感器读取异常陷入死循环

问题分析与解决方案

看起来你遇到的核心问题是while循环内部没有重新读取传感器数据——一旦进入循环,inches3inches2的值就停留在进入循环前的那次读数,只要初始条件满足(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(),实时更新inches3inches2的值,这样当传感器检测到满足退出条件时,循环会自动结束;
  • pulseIn()添加了超时参数,避免传感器无回波时程序长时间阻塞;
  • microsecondsToInches()里处理了超时返回0的情况,避免出现异常的距离值;
  • 增加了转向过程中的调试打印,方便你观察传感器数据变化。

这样修改后,机器人会在满足转向条件时进入while循环执行转向,同时持续检测传感器,一旦条件不满足就退出循环,恢复正常行驶。

内容的提问来源于stack exchange,提问作者Deon Hargrove

火山引擎 最新活动