news 2026/8/20 3:51:39

从零打造ESP-01智能开关:硬件设计、PCB绘制与MQTT通信全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零打造ESP-01智能开关:硬件设计、PCB绘制与MQTT通信全解析

1. 项目概述:从Sonoff到ESP-01的自主之路

如果你玩过智能家居,大概率听说过Sonoff这个牌子。它那些几十块钱一个的Wi-Fi开关模块,可以说是很多人入坑DIY智能家居的起点。便宜、稳定、还能刷第三方固件,确实香。但不知道你有没有想过,Sonoff本质上就是一个集成了继电器的ESP8266模块,外面套了个壳子。那么,我们能不能抛开成品,直接用最核心、最便宜的ESP-01模块,自己从头打造一个功能相同甚至更强的“Sonoff”呢?答案是肯定的,而且这个过程能让你彻底搞懂一个智能开关从硬件选型、电路设计、固件编程到云端联动的完整链条。

自己做的好处显而易见。首先是成本,一个ESP-01模块不到十块钱,加上继电器和其他元器件,总成本可以远低于品牌成品。其次是灵活性,你可以自由决定继电器的规格(是控制小台灯还是大功率空调)、接口的形态(是做成86面板还是拖线板)、以及功能的边界(是简单的定时开关,还是接入复杂的自动化平台)。更重要的是,这是一个绝佳的学习项目,它能让你从“刷机玩家”升级为“创造者”,真正理解物联网设备是如何“思考”和“工作”的。

这个项目适合谁?它适合所有对硬件和物联网感兴趣的爱好者。无论你是想省钱的实用派,还是热衷折腾的技术派,亦或是电子相关专业的学生想找个综合性的练手项目,自己动手做一个ESP-01智能开关都会让你收获满满。接下来,我会带你一步步拆解这个过程,从最基础的原理开始,直到做出一个稳定可用的产品。

2. 核心硬件解析与选型考量

自己动手,硬件是第一步。我们需要把抽象的“智能开关”概念,分解成一个个具体的电子元器件。这里的核心思想是:让ESP-01的大脑去控制一个机械开关(继电器)的手臂,同时确保整个系统供电安全可靠。

2.1 核心大脑:ESP-01模块深度剖析

ESP-01是整个项目的灵魂,它基于ESP8266芯片。很多人分不清ESP8266和ESP-01,简单说,ESP8266是芯片,而ESP-01是搭载了该芯片、并集成了必要外围电路(如晶振、Flash)的一个最小系统模块。选择ESP-01的原因很简单:极致性价比和极小体积。

但直接用ESP-01驱动继电器,会遇到几个关键问题:

  1. GPIO数量与电流驱动能力:ESP-01仅引出了两个可用的GPIO(GPIO0和GPIO2),且单个引脚最大输出电流约12mA。而一个典型的5V继电器线圈,其工作电流在70mA以上,ESP-01引脚根本无法直接驱动,强行连接会损坏模块。
  2. 工作电压:ESP-01的工作电压是3.3V,而市面上常见的继电器模块,其控制端逻辑电平虽然兼容3.3V,但线圈供电通常是5V。我们需要一个3.3V的控制信号去安全地控制一个5V的电路。
  3. 稳定性:GPIO0在模块启动时还承担着模式选择的功能(上拉为运行模式,下拉为烧录模式),在设计电路时需要特别注意,避免影响模块启动。

因此,我们的硬件设计核心,就是围绕如何让3.3V、弱电流的ESP-01去可靠地控制220V、强电流的继电器。

2.2 关键桥梁:继电器与驱动电路的选择

继电器是我们控制强电的机械手。选型时主要看几个参数:

  • 线圈电压:常见有5V和12V。为了简化电源设计,我们通常选择5V继电器。
  • 触点容量:即继电器能安全开关的负载大小,通常标注为“10A 250VAC”等。对于控制灯具、风扇等普通家电,10A足够。如果你要控制空调、热水器等,务必选择16A或更高规格的,并考虑加大散热。
  • 触点形式:常用的是“常开”(NO)和“常闭”(NC)。我们一般用常开触点,即线圈不通电时电路断开,通电后闭合。

由于ESP-01无法直接驱动继电器线圈,我们必须加入一个“驱动电路”。最经典、最可靠的选择是使用NPN型三极管(如S8050)构成一个开关电路。

电路原理简述

  1. 当ESP-01的GPIO(例如GPIO2)输出高电平(3.3V)时,电流通过一个“基极电阻”(通常1K-4.7KΩ)流入三极管的基极(B)。
  2. 三极管导通,其集电极(C)和发射极(E)之间相当于一根导线,此时继电器线圈的一端接地,形成回路,继电器吸合。
  3. 当GPIO输出低电平(0V)时,三极管截止,继电器线圈断电,触点释放。
  4. 继电器线圈是感性负载,断电瞬间会产生很高的反向电动势,可能击穿三极管。因此,必须在继电器线圈两端反向并联一个续流二极管(如1N4148),为这个反向电流提供泄放通路,保护三极管。

这是一个经过无数项目验证的经典电路,成本不到一元钱,可靠性极高。

2.3 动力源泉:电源方案设计

电源是设备的“心脏”,设计不好会带来严重安全隐患。我们的系统需要两种电压:5V(给继电器线圈供电)和3.3V(给ESP-01供电)。

方案一:线性稳压方案(适合小功率、入门)这是最简单的方法。使用一个220V转5V的AC-DC开关电源模块(注意选择隔离型,安全第一),然后通过一个AMS1117-3.3这样的线性稳压芯片,将5V降压为3.3V给ESP-01供电。这种方案原理简单,但AMS1117在压差(5V-3.3V=1.7V)上会产生热量,效率不高。

方案二:开关稳压方案(推荐,高效稳定)更优的方案是使用DC-DC降压开关稳压模块。同样是AC-DC模块输出5V,然后通过一个如MP1584EN、LM2596等高效开关降压模块得到3.3V。这种方案效率可达90%以上,发热小,更适合长期运行。现在也有很多集成的AC-DC模块,直接输出一路5V和一路3.3V,更为方便。

重要安全提示:无论采用哪种方案,涉及220V市电的部分,务必做好绝缘和隔离!强烈建议使用现成的、有安全认证的AC-DC模块,而不是自己从变压器、整流桥开始搭建。在PCB布局时,220V走线区域(强电区)和5V/3.3V走线区域(弱电区)之间必须留出足够的“电气间隙”(通常建议3mm以上),可以使用开槽(在PCB上挖一条空槽)进行物理隔离,这是保障人身安全的关键设计。

2.4 其他外围元件

  • 指示灯:可以增加一个LED和限流电阻,连接到ESP-01的另一个GPIO(如GPIO0),用于指示网络状态或开关状态。
  • 按键:可以添加一个轻触开关,连接到ESP-01的某个GPIO并接地,用于手动控制或触发配网模式。
  • 滤波电容:在ESP-01的3.3V电源引脚附近,放置一个100nF的陶瓷电容和一个10uF的电解电容,用于滤除电源噪声,这对ESP8266的Wi-Fi射频稳定性至关重要。

3. 电路设计与PCB绘制实战

有了元器件选型,接下来就是把它们合理地连接起来,并设计成可以实际焊接的电路板。这一步是理论到实物的关键跳跃。

3.1 原理图设计:从逻辑到连接

原理图是电路的“地图”。你可以使用立创EDA(国产,免费,上手快)、KiCad(开源免费,功能强大)或Altium Designer(专业,昂贵)等工具。我们以立创EDA为例,因为它对新手非常友好,且集成元器件库和PCB打样服务。

绘制要点

  1. 创建元件库:虽然立创EDA自带大量库,但像ESP-01这种特定模块,你可能需要自己绘制符号(Symbol)或从社区导入。确保引脚定义准确。
  2. 搭建核心电路
    • 放置ESP-01模块。
    • 放置5V继电器,并连接其线圈到驱动三极管电路(三极管、基极电阻、续流二极管)。
    • 将三极管的基极通过一个1kΩ电阻连接到ESP-01的GPIO2。
    • 放置电源接口(如接线端子),连接AC-DC模块的5V输出。
    • 放置DC-DC降压模块或AMS1117-3.3芯片,将5V转为3.3V,并连接到ESP-01的VCC和CH_PD(使能)引脚。
    • 务必在3.3V和GND之间,靠近ESP-01电源引脚处,放置去耦电容(如100nF和10uF)。
  3. 添加入机交互
    • 添加一个LED和220Ω限流电阻,连接到GPIO0。
    • 添加一个轻触开关,一端接GPIO0(与LED共用),另一端接地。注意:GPIO0在启动时需要上拉,通常模块内部已有,外部再加一个10kΩ上拉电阻会更稳定。
  4. 网络与调试
    • 预留一个四针的串口接口(VCC, GND, TX, RX),方便烧录程序和调试。注意:ESP-01的TX/RX电平是3.3V,如果要用USB转TTL工具连接,必须使用支持3.3V电平的,或者使用电平转换电路。

3.2 PCB布局与布线:艺术与工程的结合

原理图检查无误后,就可以切换到PCB界面进行布局布线。这是影响产品稳定性和安全性的决定性步骤。

布局黄金法则

  1. 分区明确:在脑海中或实际在板子上画线,严格区分“强电区”(220V输入、继电器触点输出)和“弱电区”(ESP-01、数字电路)。两者之间尽量远离,如果空间有限,必须保证足够的间隔(建议≥3mm)。
  2. 核心器件优先:首先放置ESP-01模块和电源模块。电源模块的输入输出电容要尽量靠近其引脚。
  3. 信号流走向:按照信号的流向(如:电源输入 -> 降压 -> ESP-01 -> 驱动 -> 继电器)来摆放元件,让走线路径尽可能直接、简短,避免绕远和交叉。
  4. 考虑散热与安装:如果需要控制大功率设备,继电器和电源模块可能会发热,布局时要考虑散热空间,不要被其他元件紧密包围。同时,考虑外壳的安装孔位和元件高度。

布线核心技巧

  1. 线宽决定电流:电流越大,线宽要越宽。对于弱电部分的信号线,10mil(0.254mm)通常足够。对于5V电源线,如果电流在500mA左右,建议20-30mil。对于220V市电走线,必须加粗!建议至少40-50mil,甚至更宽。你可以使用在线的“PCB走线宽度计算器”,根据电流和铜厚计算所需最小线宽。
  2. 强电弱电隔离:这是安全红线。强电走线和弱电走线不要平行走线,避免长距离并行,防止干扰和安全隐患。可以在两者之间开槽,即画一个没有铜皮的矩形框,进行物理隔离。
  3. 过孔的使用:合理使用过孔进行层间切换,但不要滥用。电源线和地线可以多打一些过孔,降低阻抗。信号线尽量避免不必要的过孔。
  4. 铺铜(覆铜):布线完成后,通常会在顶层和底层进行铺铜,并连接到地网络(GND)。这能提供良好的屏蔽和降低地线阻抗。铺铜时要注意与高速信号线(虽然本项目没有)的间距,以及避免出现孤立的铜皮(“孤岛”)。
  5. 丝印标注:清晰地在PCB上标注元件位号(如R1, C2)、接口定义(如“220V IN”、“LOAD”、“TX”、“RX”)。这对自己焊接调试和日后维护至关重要。

实操心得:第一次画PCB,不用追求极致紧凑。适当放宽元件间距和线宽,能大大提高焊接成功率和调试便利性。完成布线后,一定要使用设计工具的DRC(设计规则检查)功能,检查线宽、间距、短路、开路等所有规则。在发给工厂打样前,自己至少检查三遍。

4. 固件开发与MQTT通信实现

硬件是身体,固件就是灵魂。我们将使用Arduino IDE来为ESP-01编写程序,因为它生态丰富,库支持好,适合快速开发。我们的目标是让ESP-01连接Wi-Fi,并通过MQTT协议接收控制指令。

4.1 开发环境搭建与基础配置

  1. 安装Arduino IDE:从官网下载安装。
  2. 添加ESP8266开发板支持:打开“文件 -> 首选项”,在“附加开发板管理器网址”中输入:http://arduino.esp8266.com/stable/package_esp8266com_index.json。然后打开“工具 -> 开发板 -> 开发板管理器”,搜索“esp8266”并安装。
  3. 选择开发板和端口:安装后,在“工具”菜单下,选择开发板为“Generic ESP8266 Module”。根据你的ESP-01具体型号,调整Flash Size(通常为1MB或512KB)。连接USB转TTL工具,选择对应的串口端口。
  4. 安装必要的库:打开“项目 -> 加载库 -> 管理库”,搜索并安装以下库:
    • PubSubClient:用于实现MQTT客户端功能。
    • ArduinoJson:用于处理JSON格式数据(如果需要复杂指令)。

4.2 核心代码逻辑剖析

一个典型的智能开关固件包含以下几个关键部分:

#include <ESP8266WiFi.h> #include <PubSubClient.h> // 1. 网络配置 const char* ssid = "Your_WiFi_SSID"; const char* password = "Your_WiFi_Password"; const char* mqtt_server = "your.mqtt.broker.ip"; // 例如本地Mosquitto或公有云地址 // 2. 引脚定义 const int relayPin = 2; // GPIO2 控制继电器 const int ledPin = 0; // GPIO0 连接状态指示灯 const int buttonPin = 0; // 与LED共用GPIO0,注意逻辑处理 // 3. 初始化对象 WiFiClient espClient; PubSubClient client(espClient); // 4. 连接Wi-Fi void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); digitalWrite(ledPin, !digitalRead(ledPin)); // WiFi连接过程中LED闪烁 } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } // 5. MQTT回调函数(收到消息时触发) void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); String message; for (int i = 0; i < length; i++) { message += (char)payload[i]; } Serial.println(message); // 判断消息并控制继电器 if (String(topic) == "home/switch01/set") { if (message == "ON") { digitalWrite(relayPin, HIGH); // 根据你的电路,HIGH可能是吸合也可能是断开 Serial.println("Switch ON"); client.publish("home/switch01/state", "ON"); // 发布状态反馈 } else if (message == "OFF") { digitalWrite(relayPin, LOW); Serial.println("Switch OFF"); client.publish("home/switch01/state", "OFF"); } } } // 6. 重连MQTT函数 void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); String clientId = "ESP8266Client-Switch01"; // 客户端ID if (client.connect(clientId.c_str())) { Serial.println("connected"); client.subscribe("home/switch01/set"); // 订阅控制主题 client.publish("home/switch01/state", "OFF"); // 上线发布初始状态 } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } // 7. Setup 和 Loop void setup() { pinMode(relayPin, OUTPUT); pinMode(ledPin, OUTPUT); digitalWrite(relayPin, LOW); // 初始化继电器状态 Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, 1883); // MQTT默认端口1883 client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); // 维持MQTT连接,处理接收消息 // 这里可以添加按钮检测逻辑 // 如果检测到按钮按下,可以切换继电器状态并发布MQTT消息 }

代码关键点解析

  • 主题设计:采用home/switch01/set作为控制主题,home/switch01/state作为状态反馈主题。这是一种清晰的“命令/状态”分离模式。
  • 状态反馈:每次执行开关动作后,都向state主题发布当前状态。这样,任何订阅了该主题的客户端(如手机APP、家庭自动化服务器)都能实时知道开关的状态,保持界面与设备同步。
  • 遗嘱消息:更完善的实现可以在client.connect时设置“遗嘱消息”(Last Will),当设备异常离线时,MQTT代理会自动发布一条“离线”消息到指定主题,方便系统感知设备状态。
  • 按钮处理:在loop()中检测按钮,实现本地物理控制。本地控制后,也应通过MQTT发布状态更新,确保云端状态同步。

4.3 连接MQTT代理与测试

你需要一个MQTT代理(服务器)。可以选择:

  • 本地部署:在树莓派或常开机的电脑上安装Mosquitto,延迟最低,数据完全私有。
  • 公有云:使用EMQX Cloud、阿里云物联网平台等提供的免费额度,配置更简单,支持外网访问。

使用MQTT客户端工具(如MQTTX、Mosquitto自带的mosquitto_sub/pub命令)进行测试:

  1. 订阅状态主题:mosquitto_sub -h your.server.ip -t "home/switch01/state"
  2. 发布控制命令:mosquitto_pub -h your.server.ip -t "home/switch01/set" -m "ON"观察ESP-01的串口输出和继电器动作,同时状态主题应该能收到“ON”的反馈。

5. 系统集成、调试与进阶优化

当硬件焊接完成,固件也烧录进去后,就进入了联调阶段。这是问题集中爆发的环节,也是最能学到东西的环节。

5.1 上电前检查与静态测试

安全第一!在连接220V市电前,务必完成以下检查:

  1. 目视检查:检查PCB有无明显的短路、虚焊、连锡。特别是强电部分焊点是否饱满、牢固。
  2. 万用表测试
    • 测短路:用蜂鸣档,测量5V与GND、3.3V与GND之间是否短路。
    • 测通路:检查电源路径是否通畅,从输入端子到稳压芯片,再到ESP-01的VCC引脚。
    • 测继电器驱动:断开ESP-01模块,给驱动三极管的基极电阻一个模拟的高电平(例如用杜邦线接到3.3V),用万用表测量继电器线圈两端电压,应接近5V(继电器吸合);断开模拟信号,电压应为0V(继电器释放)。
  3. 低压上电测试先不要接220V!只用5V电源(如USB或电源适配器)给板子供电。测量3.3V输出是否准确稳定。观察ESP-01模块上的LED是否按预期闪烁(启动、连接Wi-Fi)。

5.2 常见问题与排查实录

即使准备再充分,第一次也难免遇到问题。这里记录几个典型“坑”:

问题1:ESP-01无法启动,串口无输出或乱码。

  • 排查
    1. 电源问题:用万用表测量ESP-01的VCC引脚电压,必须在3.2V-3.6V之间。电压不稳或过低会导致无法启动。检查3.3V稳压电路及其滤波电容。
    2. GPIO0模式:确保GPIO0在上电瞬间为高电平(上拉)。检查你的电路(如按钮、LED)是否在启动时意外将其拉低。可以尝试断开所有与GPIO0的外部连接再测试。
    3. 串口设置:确认波特率为115200,USB转TTL工具电压为3.3V。
    4. Flash模式:某些ESP-01模块需要特定的Flash模式。在Arduino IDE中尝试不同的“Flash Mode”(如DIOQIO)和“Flash Size”。

问题2:Wi-Fi连接不稳定,经常断开。

  • 排查
    1. 电源是罪魁祸首:ESP8266在发射Wi-Fi信号时瞬间电流可达200mA+。如果电源带载能力不足或纹波过大,会导致模块复位。确保你的3.3V电源能提供至少500mA的持续电流,并且电源引脚附近的10uF和100nF电容必须焊上且质量良好
    2. 软件看门狗:在loop()中如果存在长时间阻塞的代码(如delay(5000)),可能导致看门狗复位。尽量使用非阻塞的定时方式,或者适时调用delay(0)yield()来喂狗。
    3. 信号强度:检查Wi-Fi信号强度(WiFi.RSSI()),如果太弱,考虑调整位置或增加信号中继。

问题3:MQTT频繁断开重连。

  • 排查
    1. 网络问题:同问题2,先确保Wi-Fi稳定。
    2. 心跳时间PubSubClient库默认心跳间隔是15秒。如果网络延迟大,可以尝试在client.connect()前通过client.setKeepAlive(60)将其设置得更大一些。
    3. 代理服务器问题:检查你的MQTT代理服务器是否稳定,防火墙是否打开了1883端口。
    4. 客户端ID冲突:确保每个设备的客户端ID是唯一的。可以在ID中加入芯片ID:String clientId = "ESP8266Client-" + String(ESP.getChipId());

问题4:继电器动作时,ESP-01会复位。

  • 原因与解决:这是最经典的电源干扰问题。继电器吸合瞬间,线圈需要很大电流,可能导致电源电压被瞬间拉低。解决方法:
    1. 电源隔离:为继电器驱动部分单独供电,或使用光耦隔离ESP-01的控制信号和继电器的驱动电路。
    2. 加大电源储能:在5V电源入口处并联一个大容量电解电容(如470uF-1000uF),就像一个大水池,在继电器需要大电流时提供瞬时补给,缓冲电压跌落。
    3. 优化PCB布局:继电器的电源走线要粗而短,避免与ESP-01的电源走线长距离并行。

5.3 功能进阶与优化方向

当基础功能稳定后,你可以考虑以下优化,让它更“聪明”、更可靠:

  1. 配网智能化:告别硬编码Wi-Fi密码。实现SmartConfigWeb配网。例如,设备启动后若未连接网络,则进入AP模式,手机连接该AP后打开一个网页即可配置Wi-Fi和MQTT信息。可以使用WiFiManager库轻松实现。
  2. OTA升级:通过网络远程更新固件,无需再插拔USB线。Arduino IDE配合ESP8266HTTPUpdateServer库可以搭建简单的OTA服务器。
  3. 本地控制协议:除了MQTT,可以同时支持Home Assistant的本地API(如MQTT自动发现)或Apple HomeKit(通过ESP-HomeKit库),实现与主流智能家居平台的无缝集成。
  4. 多路控制与传感器集成:ESP-01只有两个GPIO是硬伤。如果需要控制多路或接传感器,可以考虑使用ESP-01的串口与一个更便宜的MCU(如STM32或Arduino)通信,由ESP-01负责网络,MCU负责复杂的本地逻辑和IO管理。或者,直接升级到GPIO更多的模块如ESP-12F。
  5. 功耗优化:对于电池供电场景,可以启用ESP8266的深度睡眠模式,定时唤醒上报状态或检查指令,极大降低功耗。

从一颗小小的ESP-01模块开始,到设计电路板、焊接元器件、编写控制逻辑、最终连接云端,这个完整的流程走下来,你收获的不仅仅是一个可以用的智能开关。你理解了强弱电隔离的安全设计,掌握了通过三极管驱动大电流负载的方法,熟悉了PCB设计从原理图到布局布线的全流程,实践了微控制器通过Wi-Fi和MQTT与外界通信的编程模式,更积累了宝贵的硬件调试和问题排查经验。这些技能是通用的,可以迁移到任何物联网设备开发中。下次当你再看到任何智能硬件产品,你都能清晰地看透它的内部逻辑,甚至知道如何去改进它。这,就是DIY最大的魅力所在。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/20 3:51:14

从Perplexity退款事件看SaaS订阅系统架构与可靠性设计

这次我们来看一个关于 Perplexity 订阅退款失误的事件。这不是一个技术部署教程&#xff0c;而是一个对近期 AI 服务商运营事件的深度技术分析。对于开发者、产品经理和关注 AI 服务商业化的读者来说&#xff0c;这类事件背后暴露的系统设计、用户权益保障和危机公关处理&#…

作者头像 李华
网站建设 2026/8/20 3:44:54

免费激活Adobe全家桶实测:Adobe-GenP如何让我5分钟告别订阅焦虑

免费激活Adobe全家桶实测&#xff1a;Adobe-GenP如何让我5分钟告别订阅焦虑 【免费下载链接】Adobe-GenP Adobe CC 2019/2020/2021/2022/2023 GenP Universal Patch 3.0 项目地址: https://gitcode.com/gh_mirrors/ad/Adobe-GenP 这篇文章不是一份教程&#xff0c;而是我…

作者头像 李华
网站建设 2026/8/20 3:42:19

河道清洁船设计全解析:从双体船体到传送带收集系统的DIY指南

1. 项目概述&#xff1a;从概念到现实的“河道清洁船”如果你曾留意过城市内河、公园湖泊或者乡村的灌溉渠&#xff0c;大概率见过这样的景象&#xff1a;水面上漂浮着塑料瓶、泡沫板、枯枝落叶&#xff0c;甚至是一些废弃的渔网和生活垃圾。这些漂浮物不仅影响景观&#xff0c…

作者头像 李华