基于CRICKIT与CircuitPython的蛇形机器人避障项目实践

发布时间:2026/5/16 3:53:26

基于CRICKIT与CircuitPython的蛇形机器人避障项目实践 1. 项目概述与核心思路最近在捣鼓一个挺有意思的创客项目用Adafruit的CRICKIT扩展板和CircuitPython做一个能自己溜达、遇到障碍会躲开的蛇形机器人。这玩意儿听起来复杂其实拆解开来核心就是“感知-决策-执行”这个经典的控制闭环。对于刚接触嵌入式硬件或者想找个具体项目练手的朋友来说它是个绝佳的切入点能把电机控制、传感器应用和逻辑编程串起来形成一个看得见摸得着的成果。整个项目的骨架很简单一个移动底盘两个轮子一个大脑Circuit Playground Express一个驱动和接口中心CRICKIT板再加上几个用来“探路”的微动开关就是咱们常说的碰撞传感器。机器人的逻辑是一边以“之”字形路线前进我们管这叫“抢风行驶”tacking一边用前方的“胡须”其实就是装了杠杆的微动开关和“鼻子”中间的开关探测障碍。一旦碰到东西它就后退一点然后朝反方向转个弯试图绕开。如果试了几次还被困住它就会“放弃挣扎”停在原地并发出蜂鸣声求救。我选择CRICKIT和CircuitPython这套组合主要是看中了它的“快速成型”能力。CRICKIT把电机驱动、舵机控制、数字/模拟输入输出都集成到了一块板上省去了自己焊接电机驱动模块、连接一堆杜邦线的麻烦。CircuitPython则让编程变得像写脚本一样简单无需复杂的编译环境代码修改后直接保存就能运行调试反馈几乎是实时的。这对于教学、原型验证或者周末在家搞点小创造来说效率提升不是一点半点。下面我就把从零搭建这个蛇形机器人到一步步给它赋予避障、报警甚至更可靠供电能力的全过程以及其中踩过的坑和总结的技巧详细分享出来。2. 硬件选型、清单与设计解析工欲善其事必先利其器。一个稳定的硬件平台是项目成功的基础。这个项目的硬件清单可以分为核心控制器、执行与感知机构、供电系统以及结构材料几个部分。我会逐一解释为什么选这些部件以及有没有可替代的方案。2.1 核心控制与驱动单元这是机器人的“大脑”和“小脑”。Circuit Playground Express (CPX)这是项目的核心微控制器。我选择它而不是Arduino Uno或者ESP32主要原因有三。第一它原生支持CircuitPython开发体验流畅第二板载了加速度计、光线传感器、温度传感器、蜂鸣器、RGB LED灯环等一大堆外设虽然这个项目里我们主要用它的GPIO和计算能力但这些额外的传感器为未来功能扩展比如根据环境光改变行为模式留足了空间第三它和CRICKIT是“官配”通过金手指插座直接插接物理连接极其稳固可靠避免了面包板连接容易松动的烦恼。CRICKIT for Circuit Playground Express这是项目的“力量与感知中枢”。它的价值在于高度集成。板载了两个直流电机驱动通道可以直接驱动我们用的TT马达无需额外的电机驱动芯片如L298N和复杂的接线。四个“驱动”输出可以输出5V PWM信号完美驱动我们的5V有源蜂鸣器。多个信号输入口支持数字输入/输出和模拟输入我们用它来读取三个微动开关的状态。板载了上拉电阻我们只需在代码中启用内部上拉无需外接电阻进一步简化了电路。电源管理为CPX和自身外设提供稳定的5V电源。选择它本质上是用一定的成本这块板子不便宜换取了极大的开发便利性和可靠性特别适合教育场景和希望快速看到成果的创作者。2.2 执行与感知机构这是机器人的“腿”和“触角”。TT马达与轮子 (x2)这是最常用的微型减速电机之一价格便宜扭矩适中。选择200RPM每分钟转数的版本速度不会太快导致控制困难也有足够的扭矩推动小车。轮子我选了橙色带胎纹的抓地力比光面轮好很多在木地板或地砖上不容易打滑。一个关键细节TT马达通常有红黑两根线。在接线时需要将两个马达以相反的极性连接到CRICKIT的电机端口1和2。这样在代码中给两个电机相同的正转速值时它们会反向旋转从而实现前进差速转向同理。如果接成同向一个电机正转会前进另一个正转会后退车子就在原地打转了。微动开关带杠杆 (x3)这是我们避障系统的“传感器”。选择带杠杆的型号可以增大触发面积就像昆虫的触角。我试过直接用按钮开关但需要非常正的碰撞才能触发而杠杆开关只要侧面轻轻刮到障碍物就能动作可靠性高得多。注意我们选用的是2引脚常开型版本。平时开关断开信号线通过CRICKIT内部上拉电阻保持高电平当杠杆被压下开关闭合信号线接地变为低电平。代码就是通过检测这个从高到低的跳变来判断碰撞的。5V有源蜂鸣器 (x1)这是报警装置。所谓“有源”就是内部自带振荡电路只要接通额定电压这里是5V就会持续发出固定频率2KHz的响声。它的优点是控制极其简单一根线接电源一根线接控制信号CRICKIT的驱动输出给高电平就响给低电平就停不需要像无源蜂鸣器那样用PWM信号来驱动发声节省了代码复杂度。2.3 供电系统方案演进供电是很多机器人项目的“暗坑”电机启动瞬间的大电流可能导致微控制器重启。基础方案AA电池盒项目初期可以使用3节或4节AA电池盒对应碱性电池或镍氢充电电池。优点是容易获取。但缺点明显电机堵转时电压下降快可能导致CPX工作不稳定电池续航一般。工具提示如果你用的电池盒输出是导线需要一个DC电源适配器公头转接成2.1mm插头才能插入CRICKIT的电源口。进阶方案锂聚合物电池升压模块这是强烈推荐的“完全体”方案。核心部件是一个6600mAh的3.7V锂聚合物电池和一个PowerBoost 1000C充电升压模块。为什么这么选这个大容量锂电提供了远超AA电池的能量并且放电曲线平稳。PowerBoost 1000C模块则解决了两个关键问题一是将锂电的3.7V升压到CRICKIT需要的5V二是集成了充电管理电路可以通过Micro USB口直接充电同时支持边充边用。它还提供了一个低电量报警LBO信号我们可以将其连接到CRICKIT的一个信号引脚在代码中检测电量过低让机器人提前“回家”或报警避免电池过放损坏。一个实用技巧PowerBoost 1000C模块上有一个“EN”使能引脚接高电平Vs时输出开启接低电平GND时关闭。我直接在它的GND、EN、Vs这三个并排的焊盘上焊接了一个SPT滑动开关实现了物理电源开关比拔插头方便多了。2.4 结构材料与辅助工具机器人得有个身体这里充分体现了“创客”精神——利用手边材料。主体结构瓦楞纸板是绝对的主角。它容易切割、打孔重量轻且有足够的强度支撑电子部件。你需要准备足够大的纸板来做底盘、碰撞挡板“胡须”和“鼻子”以及后续的蛇身装饰。连接件塑料铆钉用于连接蛇身的各个纸板节段活动灵活且外观整齐。长尾夹在调试阶段用几个长尾夹临时固定部件或作为机器人的“尾橇”非常方便。竹签可以作为加固件或者用来制作装饰性的“蛇信”。粘合与固定热熔胶枪与胶棒固定电机、开关、蜂鸣器等部件到纸板上的首选。凝固快粘接力强。但要注意电机长时间工作会发热可能软化热熔胶。所以我在电机底部先用了双面胶定位再用热熔胶在四周加固最后甚至加了扎带进行机械捆绑双重保险。双面胶用于粘贴电池、CPX等平整的部件方便拆卸和调整位置。电路连接母对公杜邦线用于连接微动开关和CRICKIT的信号端口。建议买一捆各种长度都有非常实用。排针蜂鸣器的引脚太短无法直接插入CRICKIT的接线端子。我剪了一段堆叠排针掰下中间两针只用两头的针弯曲后插入端子再把蜂鸣器插在排针上完美解决了高度和间距问题。3. 分步构建与核心代码实现有了零件接下来就是动手组装和编写“灵魂”。我会按照从简到繁的顺序分四个阶段来构建这个机器人基础移动、增加避障、添加报警、升级电源。每个阶段都有完整的代码和详细的接线说明。3.1 第一阶段搭建基础移动平台这个阶段的目标是让机器人能动起来并学会“之”字形前进。机械组装要点切割底盘用瓦楞纸板裁出一个长方形。宽度要能容纳两个TT电机并排注意电机轴是双侧突出的长度要能在电机前方留出约4厘米的空间用于后续安装碰撞传感器。宁长勿短后期可以修剪。安装电机与电池将两个TT电机用双面胶配合热熔胶加固贴在底盘后部两侧确保它们的转轴朝向一致都是向前。然后将电池盒用双面胶固定在底盘中部。重要提示为了降低重心我把所有东西都装在纸板的上表面这样底盘可以更贴近地面。但这也意味着固定电机的胶需要承受整个机器人的重量务必粘牢。安装控制器将Circuit Playground Express插入CRICKIT然后将这个整体用双面胶固定在两个电机上方。如果CPX底部不平可以垫点泡沫双面胶或者使用3D打印的CRICKIT底座这样更稳固。安装尾橇在底盘后部下方夹一个长尾夹作为滑动支点防止机器人“屁股”拖地。电路连接将两个TT电机的红线、黑线分别接入CRICKIT的Motor 1和Motor 2的端子。关键点为了让两个轮子同向旋转实现前进你需要将其中一个电机的线序反接。例如Motor 1按红正黑负接Motor 2就按黑正红负接。这样在代码里给两个电机同样的正速度它们实际旋转方向相反合力就是向前。将电池盒的2.1mm插头插入CRICKIT的5V Power接口。核心代码解析 (code.py)# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries # SPDX-License-Identifier: MIT import time from adafruit_crickit import crickit # 初始化 seesawCRICKIT的协处理器和电机对象 ss crickit.seesaw left_wheel crickit.dc_motor_1 right_wheel crickit.dc_motor_2 # 电机速度校正函数。由于电机存在个体差异即使给相同信号转速也可能不同。 # 这会导致机器人走不直。通过乘以一个校正因子来补偿。 # 例如如果机器人向右偏说明左轮快了或右轮慢了。 # 可以尝试将 set_left 的因子调小如0.95或将 set_right 的因子调大如1.05。 def set_right(speed): right_wheel.throttle speed * 0.9 # 右轮默认打9折 def set_left(speed): left_wheel.throttle speed # 左轮全速 # 调试代码取消下面几行的注释让机器人直行观察其偏向然后调整上面的因子。 # set_right(1.0) # set_left(1.0) # while True: # pass # 主循环实现“之”字形抢风移动 while True: # 向左抢风右轮全速左轮慢速机器人整体向左前方移动 set_left(0.25) set_right(1.0) time.sleep(0.75) # 持续0.75秒 # 向右抢风左轮全速右轮慢速机器人整体向右前方移动 set_left(1.0) set_right(0.25) time.sleep(0.75)实操心得电机校正这是让机器人走直线的关键。找一个开阔的直线场地运行上面的调试代码。观察机器人跑偏的方向然后微调set_left和set_right函数中的因子从1.0开始增减0.05。这是一个“观察-调整”的迭代过程可能需要几次尝试。校正完成后记得重新注释掉调试代码。速度与时间参数0.25和1.0是速度比0.75是每次“抢风”的持续时间。这些参数决定了机器人行走的“步态”。你可以调整它们来改变机器人的转弯幅度和前进节奏让它看起来更“灵动”或更“稳重”。3.2 第二阶段增加碰撞检测与避障逻辑现在让机器人拥有“触觉”能感知碰撞并做出反应。硬件加装制作“胡须”取两个微动开关。将两根母对公杜邦线的公头剪掉剥线、上锡然后焊接到开关的两个引脚上不分正负。用热熔胶将开关垂直固定在底盘前部左右两侧杠杆朝外。然后剪两块长约8cm、宽约4cm的硬纸板用热熔胶粘在开关的杠杆上作为探测杆。调整角度使其大致平行于地面且不会拖地。制作“鼻子”取第三个微动开关用热熔胶将其垂直固定在底盘前部正中间位置略低于两个“胡须”。剪一块足够宽的纸板粘在它的杠杆上用于填充两个“胡须”之间的盲区。确保“鼻子”的底边突出这样正面碰撞时一定能触发。电路连接将左、右、中三个微动开关的信号线焊接的杜邦线分别连接到CRICKIT的Signal 2、Signal 1、Signal 3端口具体端口分配可自定义与代码对应即可。开关的另一根线统一连接到CRICKIT上任意的GND端口。代码升级与逻辑解析代码变长了核心是增加了react_to_bumpers()和tack()两个函数并修改了主循环。import time import random from adafruit_crickit import crickit LEFT False RIGHT True random.seed(int(time.monotonic())) # 初始化随机数种子 ss crickit.seesaw left_wheel crickit.dc_motor_1 right_wheel crickit.dc_motor_2 # 定义三个碰撞传感器连接的信号引脚 RIGHT_BUMPER crickit.SIGNAL1 LEFT_BUMPER crickit.SIGNAL2 CENTER_BUMPER crickit.SIGNAL3 # 将引脚设置为输入模式并启用内部上拉电阻。 # 启用上拉后引脚默认被拉高到3.3V逻辑1。 # 当开关闭合引脚接地读取到的值变为0逻辑0。 ss.pin_mode(RIGHT_BUMPER, ss.INPUT_PULLUP) ss.pin_mode(LEFT_BUMPER, ss.INPUT_PULLUP) ss.pin_mode(CENTER_BUMPER, ss.INPUT_PULLUP) # ... (set_left, set_right 函数与之前相同) ... def react_to_bumpers(): attempt_count 0 while True: # 持续尝试脱困 if attempt_count 3: # 尝试3次后放弃 return True # 返回True表示“被困住” # 读取传感器状态。由于上拉未触发时为True触发时为False。 # 所以用 not 取反使得 bumped 变量在触发时为 True。 bumped_left not ss.digital_read(LEFT_BUMPER) bumped_right not ss.digital_read(RIGHT_BUMPER) bumped_center not ss.digital_read(CENTER_BUMPER) if not bumped_left and not bumped_right and not bumped_center: return False # 没有碰撞脱困成功 # 处理正面碰撞随机选择向左或向右转 if bumped_center: bumped_left random.choice([False, True]) bumped_right not bumped_left # 通用避障动作先后退0.5秒 set_left(-0.5) set_right(-0.5) time.sleep(0.5) # 根据触发侧决定转向 if bumped_left: # 碰左边向右转 set_left(1.0) # 左轮前进 set_right(0.0) # 右轮停止 elif bumped_right: # 碰右边向左转 set_left(0.0) set_right(1.0) # 随机转向时间增加行为的不确定性避免陷入固定循环 time.sleep(random.choice([0.2, 0.3, 0.4])) attempt_count 1 def tack(direction, duration): target_time time.monotonic() duration # 计算结束时间 # 根据方向设置电机开始抢风行驶 if direction LEFT: set_left(0.25) set_right(1.0) else: set_left(1.0) set_right(0.25) # 在抢风过程中持续检查碰撞 while time.monotonic() target_time: # 如果任何一个传感器被触发读取值为False则立即进入避障 routine if not(ss.digital_read(LEFT_BUMPER) and ss.digital_read(RIGHT_BUMPER) and ss.digital_read(CENTER_BUMPER)): return react_to_bumpers() # 调用避障函数并返回其结果 return False # 顺利完成本次抢风未碰撞 # 主循环 while True: # 先向左抢风如果返回True表示被困则跳出循环 if tack(LEFT, 0.75): break # 再向右抢风 if tack(RIGHT, 0.75): break # 跳出循环意味着被困或任务结束停止电机 set_left(0) set_right(0) # 程序停在这里 while True: pass避障逻辑精讲状态检测tack()函数在机器人行走时持续检查三个传感器。ss.digital_read()在开关未触发时返回True因为上拉触发时返回False。所以if not(ss.digital_read(...) and ...)这个条件会在任一传感器触发时成立。中断与响应一旦检测到碰撞tack()会立即中断当前的“抢风”动作调用react_to_bumpers()函数。这种“实时检查-中断响应”的模式是机器人控制系统中的典型设计。脱困策略react_to_bumpers()的逻辑是“后退-转向-检测”。它尝试让机器人后退一小段距离然后朝碰撞的反方向转弯。随机转弯时间是为了增加逃脱复杂地形如角落的概率。尝试次数限制3次是必要的防止机器人在死胡同里无限挣扎耗尽电力。正面碰撞处理对于中间的“鼻子”传感器我们无法判断障碍物在左在右。代码采用了一种简单有效的策略随机选择一个方向。你也可以实现更复杂的逻辑比如记录上次转向方向这次就朝另一边转。3.3 第三阶段集成蜂鸣器报警功能当机器人多次尝试仍无法脱困时让它发出声音求救这样你就知道它卡在沙发底下了。硬件加装取一个4位的堆叠排针掰掉中间两针只留两边。将这两根针稍微弯曲然后插入CRICKITDrive区域的5V和Drive 2端子。将5V有源蜂鸣器的引脚通常有标记或较长的引脚插入连接5V的排针另一个引脚插入连接Drive 2的排针。务必注意极性接反蜂鸣器不会工作。代码升级只需在主循环之后添加一个让蜂鸣器间歇鸣叫的循环。# ... (前面的所有代码包括 react_to_bumpers 和 tack 函数) ... while True: if tack(LEFT, 0.75): break if tack(RIGHT, 0.75): break # 停止电机 set_left(0) set_right(0) # 报警循环 while True: for _ in range(3): # 响3声短促的“哔” crickit.drive_2.fraction 1.0 # 打开 Drive 2蜂鸣器 time.sleep(0.1) # 响0.1秒 crickit.drive_2.fraction 0.0 # 关闭 Drive 2 time.sleep(0.2) # 停0.2秒 time.sleep(10.0) # 等待10秒后重复代码解释crickit.drive_2.fraction属性控制Drive 2输出口的占空比1.0表示持续高电平5V0.0表示低电平0V。通过快速开关形成“哔哔”声。每10秒重复一次既不会太吵又能有效引起注意。3.4 第四阶段升级至锂电供电系统为了解决AA电池在电机负载下电压不稳的问题并实现长续航和便捷充电升级电源系统。硬件改装连接PowerBoost 1000C将锂聚合物电池的插头连接到PowerBoost的BAT输入端。将PowerBoost的5V和GND输出连接到CRICKIT的5V Power输入口注意正负极。将PowerBoost的LBO低电量输出引脚用一根杜邦线连接到CRICKIT的Signal 4。LBO信号在电池电压正常时为高电平电压过低时会变为低电平。在PowerBoost的GND、EN、Vs焊盘上焊接一个滑动开关。开关拨到EN与Vs相连时开启电源拨到EN与GND相连时关闭。固定用双面胶或热熔胶将PowerBoost板固定在底盘上。将大容量锂电也用双面胶固定在底盘下方或空闲位置。代码微调在主循环中增加对低电量信号的检测。# ... (在引脚定义部分增加) ... LBO crickit.SIGNAL4 ss.pin_mode(LBO, ss.INPUT_PULLUP) # LBO信号也需要上拉 # ... (其他代码不变) ... while True: # 检查是否电量低 if not ss.digital_read(LBO): # LBO低电平有效 break # 跳出主循环停止运动进入报警模式 if tack(LEFT, 0.75): break if tack(RIGHT, 0.75): break # 停止电机 set_left(0) set_right(0) # 进入报警循环同上 while True: for _ in range(3): crickit.drive_2.fraction 1.0 time.sleep(0.1) crickit.drive_2.fraction 0.0 time.sleep(.2) time.sleep(10.0)4. 调试技巧、常见问题与进阶思路把代码烧录进去机器人却一动不动或者行为诡异别急硬件项目调试是常态。下面是我在多次实践中总结的排查清单和优化思路。4.1 系统化调试流程当机器人不按预期工作时建议按以下顺序排查问题现象可能原因排查步骤完全不动CPX灯不亮1. 电源未接通。2. 电池没电或接反。3. CRICKIT与CPX接触不良。1. 检查电源开关如有是否打开电池插头是否插紧。2. 测量电池电压检查PowerBoost输出是否为5V。3. 按下再重新插紧CPX到CRICKIT上。CPX灯亮但电机不转1. 电机接线错误或松动。2. 代码未正确上传或文件名错误。3. 电机本身损坏。1. 检查电机线是否接入正确的Motor 1/2端子是否牢靠。重点检查极性尝试交换其中一个电机的两根线。2. 确认文件已保存为code.py并位于CPX的根目录。连接电脑用Mu编辑器查看REPL是否有错误输出。3. 直接将电机线短暂接触电池3-5V看是否转动。机器人不走直线电机速度不一致。使用第一阶段提供的调试代码反复调整set_left和set_right函数中的速度校正因子。在光滑地面上测试。碰撞传感器不触发1. 开关接线错误或虚焊。2. 代码中引脚定义与实际连接不符。3. 机械结构导致杠杆未被压下。1. 用万用表通断档检查开关按下时是否导通。2. 核对代码中LEFT_BUMPER等变量定义的引脚号如crickit.SIGNAL2与CRICKIT上实际插线位置是否一致。3. 调整“胡须”或“鼻子”挡板的角度和长度确保碰撞时能有效压下杠杆。蜂鸣器不响1. 蜂鸣器极性接反。2.Drive 2输出未启用或代码错误。3. 蜂鸣器损坏。1. 检查蜂鸣器极是否接5V另一脚是否接Drive 2。2. 在REPL中手动执行crickit.drive_2.fraction 1.0看是否发声。3. 直接将蜂鸣器接5V电源测试。行为混乱如不停转向1. 传感器误触发线缆松动导致信号抖动。2. 电源电压不足导致逻辑错误。3. 代码逻辑有误如避障函数陷入死循环。1. 在REPL中循环打印三个传感器的值(ss.digital_read(pin))观察在无碰撞时是否稳定为True。2. 更换为电量充足的电池或升级为锂电方案。3. 检查react_to_bumpers函数中的循环退出条件是否严谨。4.2 结构加固与优化建议纸板原型机很酷但想玩得久还得加固一下。电机固定热熔胶在电机发热后可能失效。最佳实践先用高强度双面胶如VHB胶带粘贴电机然后在电机外壳和底盘之间用热熔胶打上几个“胶墩”辅助固定最后用两个尼龙扎带将电机和底盘牢牢绑在一起。扎带承受主要机械应力胶水主要起防滑和辅助固定作用。传感器保护微动开关的杠杆是金属的频繁碰撞可能弯曲。可以在杠杆末端用热熔胶包裹一小段牙签或塑料片增加强度且不影响触发。底盘加强如果机器人较重单层瓦楞纸板可能会弯曲。可以粘贴第二层纸板或者用竹签作为“龙骨”粘在底盘下方。线缆管理用扎带或胶带将散乱的杜邦线捆好避免被轮子卷入或钩到外物。4.3 代码与行为的进阶优化基础功能实现后可以尝试以下升级让机器人更智能更平滑的运动目前的“抢风”是突然切换速度运动较生硬。可以尝试使用simpleio库的map_range函数或者自定义缓动函数让电机速度在0.25和1.0之间平滑过渡实现更柔和的弧线运动。状态指示利用CPX板载的10个RGB NeoPixel LED用不同颜色表示机器人的状态。例如蓝色代表正常行走黄色代表正在避障红色代表被困报警绿色代表电量充足闪烁红色代表低电量。“记忆”与探索可以添加一个简单的状态机。例如如果连续三次都在同一侧触发避障可以判断该方向有大型障碍下次就尝试延长另一侧的行走时间主动探索新区域。无线控制与监控如果使用支持Wi-Fi的板卡如Adafruit的ESP32-S2系列可以加入Web服务器或MQTT客户端。这样你就可以通过手机网页实时查看传感器数据、电池电压甚至远程切换模式自主漫游/手动控制。更换传感器将接触式的微动开关换成非接触式的如超声波传感器HC-SR04或红外距离传感器。这样机器人就能在撞上之前“看到”障碍实现真正的“避障”而非“撞障”。这需要修改代码为基于距离阈值的判断逻辑。这个基于CRICKIT和CircuitPython的蛇形机器人项目就像一把钥匙打开了一扇通往实体计算和机器人控制的大门。它从最基础的电机控制教起逐步引入传感器输入、条件判断、状态机等核心编程概念最终整合成一个能与环境交互的完整智能体。过程中遇到的每一个问题——从电机跑偏到传感器误触发——都是宝贵的调试经验。最重要的是它证明了用现代易用的工具链快速实现一个有趣、有挑战性的硬件项目是完全可行的。希望这份详细的实践记录能帮助你顺利搭建出自己的那个“小家伙”并在此基础上衍生出更多属于你自己的创意。

相关新闻