游乐游手机版
首页/AI热点日报/热点详情

从零开始基于Arduino制作智能吸尘机器人实战教程

类型:热点整理2026-07-06
在当下的生活节奏里,大多数人忙于工作,很难抽出时间认真打扫屋子。解决问题的办法其实很简单——买一台家用吸尘器机器人,比如 iRobot Roomba,按个按钮就能搞定清洁。不过,这类商业产品普遍有一个问题:价格不菲。所以这次,我们打算从零打造一台简易扫地机器人,在确保功能不差太多的前提下,把成本压到

在当下的生活节奏里,大多数人忙于工作,很难抽出时间认真打扫屋子。解决问题的办法其实很简单——买一台家用吸尘器机器人,比如 iRobot Roomba,按个按钮就能搞定清洁。不过,这类商业产品普遍有一个问题:价格不菲。所以这次,我们打算从零打造一台简易扫地机器人,在确保功能不差太多的前提下,把成本压到最低。

关注过这类 DIY 项目的读者可能还记得,早前有人做过基于 Arduino 的吸尘机器人,但那台机器又笨又重,必须搭配一大块铅酸电池才能动起来。新版的 Arduino 吸尘器会紧凑得多,也更实用。核心配置上,这台机器人配备了超声波传感器和红外接近传感器——前者用来避开障碍物,让机器人能在房间里自由穿梭直到清洁完毕;后者则负责防止它从楼梯上摔下来。

构建基于 Arduino 的地板清洁机器人所需的材料

由于我们选用的都是市面上非常常见的元器件,在当地爱好商店基本都能找齐。下面是完整的材料清单,附上所有组件的实物图。

  • Arduino Pro Mini × 1
  • HC-SR04 超声波模块 × 3
  • L293D 电机驱动器 × 1
  • 5V N20 电机及安装支架 × 2
  • N20 车轮 × 2
  • 开关 × 1
  • LM7805 稳压器 × 1
  • 7.4V 锂离子电池 × 1
  • 红外模块 × 1
  • 穿孔板 × 1
  • 脚轮 × 1
  • 中密度纤维板(MDF)
  • 通用便携式吸尘器

在材料清单里特意提到了“便携式吸尘器”,下图展示的就是一款从亚马逊买来的现成产品。它的内部结构很简单:底部有三个部分——储尘仓、中间的风机电机腔,以及顶部的电池仓(带盖子)。电机是直流电机,原本通过一个开关直接连到 3V(2 节 AA 电池)。由于我们要用 7.4V 锂电池给机器人供电,所以会切断内部电池的连接,改从 5V 电源取电。去掉多余部件后,只保留两根线的电机,如下图所示。

HC-SR04 超声波传感器模块

为了检测障碍物,选用了经典的 HC-SR04 超声波距离传感器。工作原理十分直白:发射端发出超声波,遇到障碍物后反弹回来,接收端拾取回波,通过 Arduino 计算时间差就能换算出距离。之前有一篇专门介绍基于 Arduino 的超声波距离传感器的文章,对这块模块的原理做了非常详细的拆解。

用于楼梯检测的地板传感器(IR 传感器)

前面提到过,机器人需要具备检测楼梯并防止坠落的功能,这里用到了红外传感器。IR 接近传感器的工作原理也很简单:红外 LED 发出红外光,如果前方有障碍物,光线会被反射回来,由光电二极管接收。不过反射回来的信号电压很弱,需要借助运算放大器比较器来放大并输出数字信号。典型 IR 模块有三根引脚:Vcc、GND 和 OUT。通常情况下,传感器前方有障碍物时输出为低电平。利用这个特性,可以判断机器人是否还在地板上——一旦检测到输出为高电平(表明前方没有地面),就立即停止前进并转向,避免跌落。

基于 Arduino 的地板清洁机器人电路图

三个超声波传感器用来探测障碍物,所以需要把所有传感器的 GND 连到公共地线,Vcc 也并到一起。每个传感器的 Trig 和 Echo 引脚分别接到 Arduino 的 PWM 引脚上。IR 模块的 Vcc 接 5V,GND 接 Arduino 的地,OUT 引脚接数字引脚 D2。电机驱动器 L293D 的两个使能引脚接到 5V,驱动电压引脚也接 5V,因为电机本身就是 5V 的。Arduino、超声波模块、电机驱动器和电机都在 5V 下工作,电压高了会烧毁。因此使用 7.4V 锂电池,并通过 LM7805 稳压器降到 5V。吸尘器电机则直接接到主电路上。

为基于 Arduino 的地板清洁机器人构建电路

焊接工作很简单:取一小块点阵穿孔板,按照电路图把每个元器件摆好,然后依次焊牢。注意要小心操作,避免短路。另外,用两个母座来插接 Arduino Pro Mini。焊完穿孔板后,把超声波传感器的引线按对应引脚接好,如图所示。

为基于 Arduino 的地板清洁机器人建造外壳

为了构思机器人的外观,在网上搜了一圈扫地机器人图片,大多都是圆形造型,于是决定也做圆形。外壳材料有很多选择:泡沫板、MDF、纸板等,最终选了 MDF,因为它够硬,还有一定的防水性。切割起来也方便。

做法是:在 MDF 板上画出两个半径 8 厘米的圆,在大圆内部再画一个半径 4 厘米的圆,用来安装吸尘器,然后沿线裁切。接着,为车轮预留下凹槽并切除相应部分(参考图片)。最后在底部打三个小孔用于安装脚轮。接下来用支架把电机固定在底座上,脚轮也定位锁死。超声波传感器分别放置在机器人的左侧、右侧和中间;IR 模块固定在底部;别忘了在外壳侧面装好开关。如果对这一步还有疑问,下面的图片应该能帮上忙。

顶部部分,用泡沫板画了一个半径 11 厘米的圆,同样裁下来。为了在顶部和底部之间留出间隔,切了三段 4 厘米长的塑料管,用胶水粘在底部,再粘上顶部。如果乐意,可以用塑料片或其他材料把机器人侧面围起来。

基于 Arduino 的地板清洁机器人 - 代码

完整的代码附在文章末尾。核心逻辑和之前基于 Arduino 的超声波距离传感器代码类似,只是加入了地板检测。下面一步步解释代码的运作方式。这次没有用任何额外的库来解码 HC-SR04 的数据,因为基础逻辑足够简单。

首先,为三个超声波传感器分别定义 Trigger 引脚和 Echo 引脚。注意:1 号代表左传感器,2 号为前传感器,3 号为右传感器。

const int trigPin1 = 3;
const int echoPin1 = 5;
const int trigPin2 = 6;
const int echoPin2 = 9;
const int trigPin3 = 10;
const int echoPin3 = 11;
int irpin = 2;

接着定义用于存储距离的变量,类型为 int;而脉冲持续时间用 long 类型。每个传感器都有一组。此外,还定义了一个整型变量 a 来记录运动状态,后面会用到。

long duration1;
long duration2;
long duration3;
int distanceleft;
int distancefront;
int distanceright;
int a = 0;

setup() 函数里,用 pinMode() 将所有通信引脚配置为输入或输出。发送超声波需要把 Trigger 引脚设为 OUTPUT,读取 Echo 引脚则设为 INPUT。同时开启串口监视器以便调试。IR 模块的引脚也设为输入。

pinMode(trigPin1, OUTPUT);
pinMode(trigPin2, OUTPUT);
pinMode(trigPin3, OUTPUT);
pinMode(echoPin1, INPUT);
pinMode(echoPin2, INPUT);
pinMode(echoPin3, INPUT);
pinMode(irpin, INPUT);

电机驱动器的四个控制引脚也定义为输出:

pinMode(4, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(12, OUTPUT);

在主循环中,分三个模块处理三个传感器的数据。每个模块的操作相同:先确保 Trigger 引脚为低电平至少 2µs,然后拉高 10µs 产生超声波脉冲,再迅速拉低。用 pulseIn() 函数读取 Echo 引脚为高电平的持续时长,该时长对应声波往返的时间。距离 = 时长 × 0.034 / 2(声速 340m/s,往返除 2)。最后将三个距离分别存入对应变量。

digitalWrite(trigPin1, LOW);
delayMicroseconds(2);
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);
duration1 = pulseIn(echoPin1, HIGH);
distanceleft = duration1 * 0.034 / 2;

获得各方向距离后,通过 if 语句控制电机从而实现机器人运动。设定一个障碍物距离阈值(本示例为 15cm,可根据需求调整)。当左传感器前方有障碍(距离 ≤ 15cm),且其他两个方向无障碍时,通过 digitalWrite() 让机器人右转。同时检测 IR 模块的状态:如果机器人在地板上,IR 引脚输出为 LOW;反之则为 HIGH。将该值存入 int s 变量,据此控制机器人行为。

下面这段代码实现后退(当检测到地板缺失时):

if(s==HIGH) { 
  digitalWrite(4, LOW);
  digitalWrite(7, HIGH);
  digitalWrite(8, LOW);
  digitalWrite(12, HIGH);
  delay(1000);
  a=1;
}

但这里有个问题:一旦电机后退、地板重新出现,机器人又会向前,导致反复卡住。为了解决这个问题,在确认地板不存在后,将变量 a 设为 1,并让后续动作判断该状态。如果 a=1,机器人就不会再向前,而是改为左转,从而避免死循环。

下面这段代码处理正常前进的条件(需同时满足地板存在、a=0 以及障碍物情况):

if ((a==0) && (s==LOW) && (distanceleft <= 15 && distancefront > 15 && distanceright <= 15) || 
    (a==0) && (s==LOW) && (distanceleft > 15 && distancefront > 15 && distanceright > 15)) {
  digitalWrite(4, HIGH);
  digitalWrite(7, LOW);
  digitalWrite(8, HIGH);
  digitalWrite(12, LOW);
}

右转的代码:

if ((a==1) && (s==LOW) ||
    (s==LOW) && (distanceleft <= 15 && distancefront <= 15 && distanceright > 15) ||
    (s==LOW) && (distanceleft <= 15 && distancefront <= 15 && distanceright > 15) ||
    (s==LOW) && (distanceleft <= 15 && distancefront > 15 && distanceright > 15) ||
    (distanceleft <= 15 && distancefront > 15 && distanceright > 15)) {
  digitalWrite(4, HIGH);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(12, HIGH);
  delay(100);
  a=0;
}

左转的代码:

if ((s==LOW) && (distanceleft > 15 && distancefront <= 15 && distanceright <= 15) ||
    (s==LOW) && (distanceleft > 15 && distancefront > 15 && distanceright <= 15) ||
    (s==LOW) && (distanceleft > 15 && distancefront <= 15 && distanceright > 15)) {
  digitalWrite(4, LOW);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(12, LOW);
}

// 定义引脚
const int trigPin1 = 3;
const int echoPin1 = 5;
const int trigPin2 = 6;
const int echoPin2 = 9;
const int trigPin3 = 10;
const int echoPin3 = 11;
int irpin = 2;

// 定义变量
long duration1;
long duration2;
long duration3;
int distanceleft;
int distancefront;
int distanceright;
int a = 0;

void setup() {
  pinMode(trigPin1, OUTPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(trigPin3, OUTPUT);
  pinMode(echoPin1, INPUT);
  pinMode(echoPin2, INPUT);
  pinMode(echoPin3, INPUT);
  pinMode(irpin, INPUT);
  pinMode(4, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(12, OUTPUT);
}

void loop() {
  digitalWrite(trigPin1, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin1, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);
  duration1 = pulseIn(echoPin1, HIGH);
  distanceleft = duration1 * 0.034 / 2;
  Serial.print("距离1:");
  Serial.println(distanceleft);

  digitalWrite(trigPin2, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin2, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);
  duration2 = pulseIn(echoPin2, HIGH);
  distancefront = duration2 * 0.034 / 2;
  Serial.print("距离2:");
  Serial.println(distancefront);

  digitalWrite(trigPin3, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin3, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin3, LOW);
  duration3 = pulseIn(echoPin3, HIGH);
  distanceright = duration3 * 0.034 / 2;
  Serial.print("距离3:");
  Serial.println(distanceright);

  int s = digitalRead(irpin);

  if (s==HIGH) {
    digitalWrite(4, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(12, HIGH);
    delay(1000);
    a=1;
  }

  if ((a==0) && (s==LOW) && (distanceleft <= 15 && distancefront > 15 && distanceright <= 15) ||
      (a==0) && (s==LOW) && (distanceleft > 15 && distancefront > 15 && distanceright > 15)) {
    digitalWrite(4, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(12, LOW);
  }

  if ((a==1) && (s==LOW) ||
      (s==LOW) && (distanceleft <= 15 && distancefront <= 15 && distanceright > 15) ||
      (s==LOW) && (distanceleft <= 15 && distancefront <= 15 && distanceright > 15) ||
      (s==LOW) && (distanceleft <= 15 && distancefront > 15 && distanceright > 15) ||
      (distanceleft <= 15 && distancefront > 15 && distanceright > 15)) {
    digitalWrite(4, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(12, HIGH);
    delay(100);
    a=0;
  }

  if ((s==LOW) && (distanceleft > 15 && distancefront <= 15 && distanceright <= 15) ||
      (s==LOW) && (distanceleft > 15 && distancefront > 15 && distanceright <= 15) ||
      (s==LOW) && (distanceleft > 15 && distancefront <= 15 && distanceright > 15)) {
    digitalWrite(4, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(12, LOW);
  }
}
来源:https://m.elecfans.com/article/1869356.html

相关热点

继续查看同栏目近期热点。

延伸阅读

补充最近整理过的热点入口。