news 2026/9/9 12:04:55

嵌入式AI实战:在RT-Thread MCU上跑通工业质检视觉Demo

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式AI实战:在RT-Thread MCU上跑通工业质检视觉Demo

1. 这个命题背后,到底想让大家做什么

先说结论:这届RT-Thread嵌入式AI创意赛的工业质检赛道,不是要你造一个完整的工业检测系统,也不是逼你去搞一套需要几百万样本才能训练出来的大模型。它的核心命题是——能不能用消费级的MCU、有限的RAM和Flash,跑通一个具备实际意义的视觉质检Demo

很多人一听"工业质检AI"就觉得门槛高得离谱。实际拆开看,工业质检在最简单的场景下就是一个图像分类问题:传送带送过来一个工件,拍一张照片,判断它是有缺陷还是正常。缺陷可能是划痕、可能是脏污、可能是形状偏移,但归根结底是"这张图是不是和标准品长得不一样"。

这个题目选得挺聪明。它既不要求你有工业现场的设备,也不依赖特定的硬件平台,一块带摄像头的开发板加一个RT-Thread系统就能起步。真正考察的是三件事:你能不能把图片数据变成模型能吃的张量,能不能把训练好的模型压到MCU能跑的体积,能不能在RT-Thread上把摄像头采集、图像预处理、AI推理、结果输出这条链路完整地串起来

从往年的参赛作品来看,这个赛道的评委其实很看重两样东西:一是整个链路的完整性,二是资源消耗的合理性。你不需要刷到99.9%的准确率,但你需要证明你的方案在低成本硬件上有落地可能。这恰恰是RT-Thread生态擅长的事情——把一个在Linux上很容易实现的功能,硬生生地塞进资源受限的嵌入式环境里。

2. 工业质检AI在嵌入式端的技术底座

2.1 问题的本质:从图像到决策的整个链条

工业质检AI看起来是个算法问题,真正做起来其实是个系统工程。我建议你从输入端开始梳理整个链条,而不是一上来就盯着模型结构。

完整的嵌入式视觉质检链路是:图像采集(摄像头)→ 图像预处理(格式转换、缩放、归一化)→ AI推理(模型前向计算)→ 结果判定(阈值或后处理逻辑)→ 控制输出(串口/GPIO/LCD显示)。每一环都有坑,而且坑往往不在AI本身。

图像采集环节最容易出问题的是数据格式。MCU端的摄像头一般是RGB565或者YUV422输出,而大多数图像分类模型接受的是RGB888输入,且尺寸是固定的(比如96x96、128x128)。如果你在PC上训练时用的是224x224的ImageNet标准输入,直接搬到MCU上,单次推理的内存占用和耗时都会让你怀疑人生。所以从数据准备开始,就要想好端侧推理时的输入尺寸。

图像预处理这块,很多人忽略了一个小细节——归一化参数。PC端训练时用的mean、std值,移植到MCU端必须原样保留。很多时候模型在PC上测试准确率很高,部署到MCU上就"失灵",不是模型坏了,是预处理不一致。举个例子,训练时图像除以255归一化到0~1,端侧推理却直接把原始像素值喂进去,模型的神经元输入分布就全乱了。

2.2 模型的选型思路:效仿TinyML的流派

嵌入式端的AI模型选型,说白了就是三个字:小、快、省。小是指模型参数量不能太大,快是指推理延迟要跟上产线节拍,省是指运行时的RAM和Flash占用要可控。

我先给一个经验值范围。对于Cortex-M4或Cortex-M7级别的MCU,主频在200MHz到480MHz之间,Flash在1MB到2MB之间,RAM在256KB到1MB之间,这类硬件跑一个二分类或多分类的轻量视觉模型,单次推理时间控制在100ms以内是合理目标。

模型架构上,我建议优先考虑MobileNetV1、MobileNetV2这种深度可分离卷积网络,或者是自己魔改的超轻量CNN(几个卷积层加全连接层)。MobileNetV2的alpha参数(宽度因子)调到0.25甚至0.1,可以非常激进地压缩模型体积。如果你觉得MobileNet还是不够小,还有一个思路是使用知识蒸馏,用一个大的教师网络指导一个小学生网络学习,学生网络可以用很简单的结构逼近教师网络的精度。

我自己做过一个实验:用MobileNetV2(alpha=0.25)训练一个5分类的工件缺陷识别模型,输入96x96x3,参数量大约80万,TensorFlow Lite格式的模型文件约320KB,转换成C数组后塞进MCU的Flash完全没问题。这个规模对于大多数工业质检场景(划痕、脏污、缺损、正常)来说,精度完全够用。

2.3 训练还是用现成模型:看你手头有多少数据

工业质检AI的数据获取是老大难问题。缺陷样本本来就少,良品样本一大堆,正负样本极度不均衡。很多参赛选手栽就栽在数据上——不是模型跑不起来,而是模型"没见过"足够多的缺陷类型。

我的建议是两条腿走路:一是网上找公开的工业缺陷数据集(比如钢铁表面缺陷数据集NEU-DET、PCB板缺陷数据集等),先跑通整个链路;二是自己构造数据增强策略,把有限的缺陷样本通过旋转、平移、亮度变化、噪声叠加等方式扩充到足够的规模。数据增强不是锦上添花,在样本少的情况下它就是雪中送炭。

如果时间实在来不及训练一个自己的模型,也可以先用别人训练好的模型做迁移学习。比如用ImageNet预训练的MobileNetV2,冻结前面的卷积层,只训练最后的分类层,这样只需要少量数据就能微调出一个可用模型。这也是我比较推荐参赛者走的捷径——不是每块砖都要自己烧,站在前人的肩膀上把任务跑通,才是工程化思维

3. RT-Thread上的AI推理框架选型与集成

3.1 推理框架对比:TFLite Micro、ONNX Runtime、还是自研C代码

在RT-Thread上跑AI推理,主流的方案有这么几条路,我逐个说优缺点。

第一条路是TensorFlow Lite for Microcontrollers(TFLite Micro)。这是Google专门为MCU设计的推理引擎,支持Cortex-M系列,自带内存分配器,可以把模型和解释器都跑在MCU上。RT-Thread的软件包仓库里有TFLite Micro的移植包,直接通过env工具或者RT-Thread Studio的包管理器拉取就行。优点是与TensorFlow生态兼容性最好,模型转换工具链成熟;缺点是代码体积偏大,对Flash较小的芯片有点吃不消。

第二条路是ONNX Runtime的嵌入式版本。ONNX的优点在于模型格式通用性强,PyTorch、TensorFlow、PaddlePaddle训练出来的模型都可以转成ONNX,再转成端侧格式。但老实说,ONNX Runtime在MCU端的生态没有TFLite Micro成熟,多数时候需要自己裁剪编译,RT-Thread上虽然有相关社区贡献包,但踩坑概率更高。除非你对ONNX已经很熟,否则我不建议作为首选。

第三条路是手工将模型权重导出为C数组,自己写推理代码。这个方法看起来土,但其实在工业场景里非常常见。尤其对于一些你自己设计的极简CNN,网络结构就几层,卷积、池化、全连接、激活函数,加起来不过几十行C代码。你只需要写一个Python脚本,把训练好的权重和偏置导出成头文件里的const数组,然后在C代码里按顺序做前向传播即可。

我个人的建议是:如果目标是快速完赛、稳定跑通,选TFLite Micro;如果目标是深度展示技术能力、并且模型是自己设计的极简结构,那就自己写推理代码。两种方案我都在RT-Thread上试过,各有千秋。TFLite Micro省心但体积大,自研代码灵活但工作量大。

3.2 用RT-Thread Studio搭建工程的实际过程

不管选哪种推理框架,工程搭建的思路是一致的。我把TFLite Micro这条路线的步骤写出来,这是我最熟悉的,也是成功率最高的。

第一步,创建RT-Thread工程。打开RT-Thread Studio,新建一个基于芯片的裸机工程,选择你手头的开发板芯片型号(STM32F407、STM32H743、RA6M4等都可以),或者直接选择官方BSP里的评估板型号。RT-Thread Studio会自动生成包含内核、Shell(FinSH控制台)的基础工程。

第二步,配置SDK和软件包。在RT-Thread Settings里,打开软件包中心,搜索"TFLite Micro"或者"TensorFlowLiteMicro",选择合适版本添加。同时还需要添加摄像头驱动包(如果你的开发板不带摄像头,可以虚拟一个图像数据源,或者用SD卡里的图片文件模拟)。我建议同时开启FinSH组件,这样调试时可以命令行交互,非常方便。

第三步,把模型文件放进去。将第2节中生成的model.tflite文件转换成C数组(可以用xxd -i命令生成一个C语言头文件),放到工程的applications目录下,然后在代码里声明这个数组并加载。TFLite Micro提供了一套API来处理模型的加载和推理,具体代码如下:

#include "tensorflow/lite/micro/all_ops_resolver.h" #include "tensorflow/lite/micro/micro_interpreter.h" #include "tensorflow/lite/micro/micro_mutable_op_resolver.h" #include "tensorflow/lite/schema/schema_generated.h" // 声明模型数据 extern const unsigned char g_model[]; extern const unsigned int g_model_len; // 定义推理用的张量内存池大小(建议根据模型调试后调整) constexpr int kTensorArenaSize = 128 * 1024; uint8_t tensor_arena[kTensorArenaSize]; // 创建解析器和解释器 static tflite::MicroMutableOpResolver<10> resolver; static tflite::MicroInterpreter* interpreter = nullptr; void ai_model_init(void) { // 注册需要的算子类型 resolver.AddConv2D(); resolver.AddDepthwiseConv2D(); resolver.AddFullyConnected(); resolver.AddSoftmax(); resolver.AddAveragePool2D(); resolver.AddReshape(); // 创建解释器 static tflite::MicroInterpreter static_interpreter( tflite::GetModel(g_model), resolver, tensor_arena, kTensorArenaSize); interpreter = &static_interpreter; // 分配张量空间 TfLiteStatus allocate_status = interpreter->AllocateTensors(); if (allocate_status != kTfLiteOk) { rt_kprintf("AllocateTensors failed\n"); } }

这里有个很重要的地方:算子注册列表必须覆盖你模型中用到的所有算子类型。如果你在训练模型时用了TFLite Micro不支持的算子(比如某些高级激活函数、注意力机制等),转换时就要把它们去掉或替代。所以训练阶段就要有"端侧思维",尽量避免使用特殊算子。

第四步,编写图像预处理和后处理逻辑。图像从摄像头拿到后是原始帧,你需要做RGB888转换、尺寸缩放(比如缩放成96x96)、归一化处理,然后填入模型输入张量。推理完成后从输出张量取出各类别概率,用argmax找到最大类别,再结合预设阈值做最终判定。后处理逻辑里建议加一个置信度过滤:如果最大概率低于0.6,就标记为"不确定",而不是强行归类。这在工业场景中更实用,因为误报比漏报更麻烦。

第五步,上板调试。编译烧录后,在FinSH控制台里输入模型初始化命令和单次推理命令,验证输出结果是否合理。调试阶段建议先把输入数据固定下来(比如内存里放一张测试图片的像素数组),排除摄像头驱动的干扰,等推理逻辑确认无误后再接入实时视频流。

3.3 数据通路设计:摄像头帧率与推理速度的博弈

工业质检对实时性是有要求的。一条典型的产线,传送带速度如果是每秒0.5米,相机视野宽度20厘米,那么每帧只能停留约400ms。这意味着从拍照到输出结果的时间预算可能只有200~300ms,留给你推理的时间窗口非常紧。

在MCU上,图像采集和AI推理是串行还是并行,是个策略问题。最简单的方式是串行:采集一帧,推理一帧,输出一次结果。但这样帧率会很低,可能只有2~5FPS。如果产线对连续检测要求高,就得考虑双缓冲机制——摄像头DMA将图像写入缓冲区A时,CPU同时推理缓冲区B中的上一帧数据。RT-Thread的信号量机制非常适合用来实现这种Producer-Consumer模型,摄像头中断里释放"帧就绪"信号量,推理线程阻塞等待该信号量。我建议使用双缓冲,这是性价比最高的优化手段,代码量不大但吞吐量直接翻倍。

另外,推理时间并非只有模型计算时间,还包括图像预处理耗时。96x96的RGB888图像,用纯C做缩放和归一化,在Cortex-M7上大概需要10~20ms,这个量级必须提前计入时间预算。

4. 模型轻量化与压缩:把模型塞进Flash的关键操作

4.1 量化:从Float32到Int8的跃迁

部署到MCU上的模型,几乎必须做8bit整型量化。原因是浮点运算在无FPU(浮点运算单元)的MCU上慢得离谱,在带FPU的M4/M7上也只是勉强能看,而int8的定点运算配合CMSIS-NN优化库,速度可以快5~10倍,同时模型体积直接缩小到原来的四分之一。

PyTorch训练好的模型是float32精度的权重,要变成int8可部署模型,标准流程是先转成TensorFlow的SavedModel格式(这一步可能有点绕),再通过TensorFlow Lite Converter做后训练量化(Post-training Quantization)。转换前后的精度损失,对于简单的缺陷分类任务通常在1%~3%之间,完全可接受。

转换时有个关键参数是代表性数据集(Representative Dataset)。量化需要一小部分真实输入数据来统计各层激活值的分布范围,从而确定量化参数(scale和zero_point)。很多人随便拿几张图就糊弄过去,结果量化后精度崩了。正确做法是拿训练集里覆盖各个类别的样本,每类至少5~10张,数量不用多,但分布要均匀。

4.2 剪枝与知识蒸馏:锦上添花的技巧

如果你的模型用的是自研超大网络(比如层数很多),或者老师模型微调出来的学生模型还是超过了MCU的内存预算,那就必须上剪枝和知识蒸馏这些进阶手段。

剪枝的核心思想是:不是所有神经元和连接都是重要的,我们可以把权重接近零的通道或连接去掉,然后微调剩余的网络恢复精度。PyTorch的torch.nn.utils.prune模块提供了一些基础的剪枝工具,可以按L1范数对卷积核做通道剪枝。实操下来,剪掉30%~50%的通道,精度损失通常在2%以内,但模型体积能明显缩小。

知识蒸馏的思路更有意思:一个参数量上百万的大模型(教师)在ImageNet或大规模数据集上训练好,然后让一个只有几十万参数的小模型(学生)去模仿它的输出概率分布——不是训练集里硬标签(一热编码),而是教师模型输出的soft probability(软化后的概率)。这样学生模型能学到类别之间的相似关系(比如"划痕"和"脏污"之间有多像),比直接在大数据集上训练小模型效果更好。

我举个实际的数值感受一下:一个5分类的缺陷识别模型,直接训练ResNet18然后裁剪,得到的模型大小约2.3MB,Flash根本塞不下。但用MobileNetV2(alpha=0.25)加知识蒸馏,精度只掉了1.2%,模型大小只有420KB,放进1MB Flash绰绰有余。工程上,选对模型结构比疯狂调参重要得多

4.3 模型验证闭环:不要等到上板才测试

模型部署的失败案例太多了,而且往往是在最后一步才暴雷。建议你在PC端就做一个"模拟部署验证":把训练好的模型按照和端侧完全一致的预处理方式(归一化参数、输入尺寸)写一个Python推理脚本,对测试集样本做推理,记录精度和混淆矩阵。然后用TFLite Converter量化后的模型跑同一个测试集,对比精度差异。

这个闭环验证能帮你提前暴露90%的部署问题。我自己曾经吃过一个大亏:训练时图片做了随机水平翻转增强,但端侧部署时忘了对输入做相同的翻转处理,导致模型在实拍图像上几乎全部识别错误。这种问题在PC端模拟部署时一下子就能发现。

5. 从命题到作品的完整技术路线与加分项

5.1 推荐的开发路线图

如果从零开始做一个参赛作品,我建议按这条时间线推进:

第一周,确定硬件平台和数据集。先不管AI部分,把RT-Thread工程搭起来,摄像头能出图,LCD能显示,FinSH能交互。数据集选公开的工业缺陷集,先跑通一个PC端的训练脚本,确保有可用的模型权重。

第二周,做模型轻量化。把训练好的模型转成TFLite格式,做int8量化,写一个PC端的模拟部署验证脚本,对比量化前后精度。同时把模型转成C数组,集成到RT-Thread工程的代码中。

第三周,联调整个数据通路。把摄像头采集、图像缩放、归一化、模型推理、结果输出串起来。先用静态图片测试,跑通后切到实时视频流。优化时间预算,确保单帧处理在200ms以内。

第四周,打磨细节,准备文档和演示。增加置信度过滤、结果可视化、异常报警等功能,录制演示视频,准备技术文档和PPT。别忘了做压力测试——连续运行1小时以上,观察内存泄漏、看门狗超时等问题。

5.2 评委眼里的加分项

根据我以往做评委和观摩比赛的经验,这类命题赛事的作品评分通常会看重这几个维度,你可以针对性设计:

第一,方案的通用性。你的代码是不是只能跑在特定的一张板子上?如果能把摄像头接口抽象成统一的设备驱动,把AI推理封装成独立模块,那么换个MCU平台只需要改底层配置,这就是很好的软件工程素养。

第二,资源使用说明的清晰度。Flash占用多少、RAM峰值多少、CPU占用率多少、单帧耗时的分项统计(采集耗时、预处理耗时、推理耗时、输出耗时)——这些数据一定要测出来并写进文档,它能直接证明你对端侧资源管理的理解深度。

第三,实用的业务逻辑。不要只做"看到缺陷就报警"这种最朴素的逻辑。可以做缺陷分类计数、连续多帧判定确认(消除偶发误报)、支持多阈值档位切换(根据产线速度自动调整灵敏度)等。这些小功能不需要太多额外开发量,但会让作品从"能跑"升级为"可用"。

5.3 真正能让评审记住你的一个额外技巧

分享一个我在实际项目中总结的小技巧:给模型输出叠加一个"数据分布可视化"层。在LCD屏上把每次推理输出的各类别概率用条形图实时显示出来,同时打点记录最近一段时间内每个类别的概率走向。这听起来像是一个展示功能,但它实际上是一个非常好的调试工具和用户信任构建器。当你向评委演示时,一块屏幕上同时显示实时视频、AI判定结果和置信度分布,比单纯输出一个"OK/NG"文字要有说服力得多。

实现方式也很简单:FinSH或者LVGL的波形控件都可以。RT-Thread的社区里有很多LVGL移植案例,直接拿来改改就行。这个功能还能帮你发现模型的隐蔽问题——比如某个类别的置信度总是在临界值徘徊,说明特征学习得不够充分,需要回去加强数据。

6. 容易踩的坑和实际调试经验

先说一个我踩过最痛的坑:TFLite Micro的算子内存分配爆掉。TensorFlow Lite的MicroInterpreter在AllocateTensors阶段会从tensor_arena分配内存,这个大小很难一次估算准。如果你的模型比较大,而tensor_arena开小了,AllocateTensors会直接返回kTfLiteError,且不会告诉你具体需要多大。我当时是二分法去试,从64KB一路试到128KB才成功。后来我发现一个技巧:用官方提供的Python脚本提前计算需要的arena大小,或者在代码里临时把arena开大一点,然后打印interpreter->arena_used_bytes()看看实际用了多少,再精确调整。记住,arena开太大浪费RAM,开太小分配失败,建议留出10%~15%的余量。

第二个坑是CMSIS-NN加速库的启用。如果你的MCU是Cortex-M4或M7,TFLite Micro是可以用CMSIS-NN做算子加速的。但在RT-Thread的软件包集成里,默认可能没有开启这个选项。需要在编译宏里加上TF_LITE_USE_CMSIS_NN,并且把CMSIS-DSP和CMSIS-NN源码加进工程编译。启用后性能差别巨大——卷积算子可以快2~4倍。不过要注意,CMSIS-NN对内存对齐有要求(通常是16字节对齐),如果数据对齐没做好,可能会触发HardFault。

第三个看似小但很多人中招的坑是打印日志拖慢推理速度。调试阶段为了方便,很多人在每帧推理前后打串口日志。但如果你的FinSH串口波特率设置偏低(比如115200),每帧日志打印可能会白白消耗几十毫秒。量产或比赛演示时,一定要把推理主路径上的日志级别调高,或者直接关闭。我建议在演示版本里只保留运行状态异常时的错误日志,避免串口输出拖后腿。

还有一个容易被忽略的是摄像头初始化时序。很多摄像头模组上电后需要一个稳定时间(通常几十到几百毫秒),如果复位后立即初始化可能失败,或者输出花屏。这部分在RT-Thread的驱动里通常已经有处理,但如果你自己写初始化代码,一定记得加延时。否则实拍时显示出的图像永远是花的,你还以为是摄像头坏了。

数据方面的坑在于缺陷样本的不均衡处理。如果你的数据集中良品占95%,缺陷品只占5%,模型训练出来会倾向于把所有样本都判为良品(因为只要全判为良品,准确率就是95%)。这个数字看着很高,实际上模型什么都没学到。应对方法有几种:过采样缺陷样本,让每个batch里缺陷样本占比稳定在40%以上;或者在损失函数里给缺陷类加大权重;最暴力的方法是用数据增强把缺陷样本的数量扩到和良品接近甚至更多。工业质检里,漏检一个缺陷的代价远大于误报,所以数据分布一定要往缺陷类倾斜,不能让模型偷懒。

最后说一说看门狗和低功耗的取舍。有些参赛作品在演示时突然死机,非常掉分。在AI推理主循环里,如果单帧处理时间接近甚至超过看门狗超时时间,就可能出现看门狗复位。这时候要么把看门狗超时时间调大(比如10秒),要么在关键步骤之间喂狗。另外,如果用了低功耗模式(比如进入睡眠等待按钮触发检测),得确认唤醒后所有外设重新初始化正常。我建议参赛作品直接禁用低功耗,稳定第一,功耗永远不是嵌入式AI视觉项目的主要矛盾。

提示:以上几个坑,每一个都是我在真实项目里一个一个填过来的。你提前知道,至少能在比赛现场少掉几次电。

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

CPO系统里的高集成度AFE:32路Heater Bias与128路监控通道如何落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 12:04:50

Browser-use实战指南:用AI Agent自然语言驱动UI自动化测试

做测试这么多年&#xff0c;我发现自己最烦的不是用例设计&#xff0c;而是写UI自动化脚本——尤其是那种要精确到按钮class、输入框id的脚本。直到我把Browser-use接进测试环境&#xff0c;用它跑通第一个登录用例&#xff0c;才意识到这个开源浏览器自动化框架跟Selenium、Pl…

作者头像 李华
网站建设 2026/9/9 12:04:45

ArmNN源码深度评测:从子图切分到边缘AI部署实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/9 12:03:26

OpenClaw实战:阿里云ECS上部署多渠道AI代理助手

我第一次跑通OpenClaw接进钉钉群的那个晚上&#xff0c;脑子里冒出来的一个念头是&#xff1a;这东西终于从一个命令行玩具&#xff0c;变成了一个能挂在工作群里长期干活的“AI员工”。如果你还没接触过OpenClaw&#xff0c;可以用一句话先理解它&#xff1a;一个开源的AI代理…

作者头像 李华
网站建设 2026/9/9 12:00:34

从零搭建AI Agent消息中枢:hermes-agent架构设计与实践

做AI Agent这段时间&#xff0c;我越来越觉得&#xff0c;工具链里缺一个真正能“跑起来”的消息中枢。很多项目都是模型很强、Prompt写得很花&#xff0c;但落到实际任务上&#xff0c;各种工具调用、状态同步、记忆管理的问题就全冒出来了。hermes-agent 这个名字&#xff0c…

作者头像 李华
网站建设 2026/9/9 11:57:31

头歌实践教学平台:Java入门-分支结构(四)

第6关&#xff1a;来吧&#xff0c;我是BOSS&#xff01;任务描述 结合本章节所学内容&#xff0c;完成本关所有的编程题。相关知识 扫描仪&#xff08;Scanner&#xff09;已经创建&#xff0c;用户输入的数据也已经获取&#xff0c;请按照题目要求通关。第一题 编写一个Java程…

作者头像 李华