news 2026/10/3 12:41:25

33 嵌入式操作系统 | 模块七验收:端到端一键验收 + 项目答辩

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
33 嵌入式操作系统 | 模块七验收:端到端一键验收 + 项目答辩

嵌入式操作系统 | 模块七验收:端到端一键验收 + 项目答辩

本课程开源地址(Gitee):https://gitee.com/fujianxinxi/qianrushixitongyingyongkaifa.git
课件、示例代码与验收脚本都在该仓库,可直接git clone或下载 ZIP 使用。

模块七 · 2 学时 · 环境:Ubuntu(完整项目环境)+ socat 虚拟串口

一句话概述:这节课不写新功能,只做两件事——① 用acceptance.sh一键把整条链路重跑一遍,逐项打勾(本节实测27 项全通过);② 按《验收清单》自评、按《答辩提纲》演练 5 分钟讲解。学完这节,你手上有一个能演示、能交付、能自愈的小系统。

本节目标

  1. 会用"一条命令 + 一个现象"的方式证明每个功能点(这就是回归测试的思路)
  2. 能独立跑通acceptance.sh,看懂每一项检查在验什么、失败时怎么查
  3. 会按《验收清单》给自己打分(A 功能 60 / B 健壮性 20 / C 工程化 12 / D 交付答辩 8)
  4. 能按《答辩提纲》讲清架构、演示主流程、回答原理题

一、讲解内容

1.1 知识讲解

① 验收和"我觉得能跑"的区别.验收的核心是可复现的证据:

不行的说法验收要的写法
“网页能控制设备”执行wget -qO- 'http://127.0.0.1:5000/cmd?name=led_on',4 秒后ubus call device status里"led": 1
“掉线能发现”杀掉面板,6 秒后/api/state里"online":0;重启面板 6 秒后变回1
“挺健壮的”灌一帧坏 CRC,网关日志出现"串口帧 CRC 失败…丢弃",之后ser_rx继续增长

②acceptance.sh的设计思路(十项,27 个检查点)

段检查什么用到的组件
①环境:socat / libubox / libubus / Flask / pyserial / uci+ubus / systemd课时 15、24
②虚拟串口建立socat
③设备面板在发帧 + 网关起来了 + 认到设备课时 26、31
④状态表正确(online=1、ser_rx>0)课时 29、31(ubus)
⑤每 2 秒0x81上报课时 29
⑥网页显示在线 + 点按钮能改状态课时 30
⑦掉线判 0 / 恢复判 1课时 29、30
⑧灌坏帧后照常工作课时 32
⑨systemd 服务化 +kill -9自愈课时 32
⑩清理现场(进程/端口/服务)全部

脚本的骨架非常朴素——一个计数器 + 两种打印:

PASS=0;FAIL=0ok(){echo" [通过]$1";PASS=$((PASS+1));}bad(){echo" [失败]$1";FAIL=$((FAIL+1));}command-vsocat>/dev/null&&ok"socat 已安装"||bad"socat 未安装"最后:if["$FAIL"-eq0];thenecho"验收通过";elseecho"有$FAIL项没过";fi

③ 为什么必须"一键"?十个检查点手工做一遍要十几分钟,而且容易漏;写成脚本以后:每次改代码都重跑一遍(回归测试),改坏了立刻能发现是哪一项坏了。这也解释了课时 32 为什么要搞故障注入——验收里必须包含"坏情况"。

④ 验收清单(100 分)与答辩(5 分钟)见同目录两份文件:

  • 代码/课时33-项目验收/验收清单.md:A 功能 60 分、B 健壮性 20 分、C 工程化 12 分、D 交付答辩 8 分,每项都写了"怎么证明"
  • 代码/课时33-项目验收/答辩提纲.md:5 分钟时间分配 + 12 个常问问题 + 加分/扣分项

⑤ 整个模块七做出来的东西(复习地图)

课时做了什么关键文件
24环境 + 协议契约check_env.py、hello_qt.py、hello_flask.py、协议契约.md
25设备面板界面(PyQt5)device_panel.py/device_panel_full.py
26面板接串口(半帧/CRC/断线重连)device_panel_serial.py、serial_monitor.py
27网关雏形:串口 ⇄ UDPgateway.c、udp_client.py
28网关 TCP 命令通道(粘包/半包/多客户端)gateway_tcp.c、tcp_client.py
29状态表 + 每 2 秒上报 + 在线判定gateway_full.c、state_listener.py
30网页上位机(显示 + 控制闭环)app.py
31产品化:配置读 uci + 状态走 ubusgateway_pro.c、device.conf、ubus_query.sh
32可靠性:故障注入 + systemd 自愈fault_device.py、fault_tcp.py、gateway.service、install_service.sh
33验收:一键端到端 + 答辩acceptance.sh、验收清单.md、答辩提纲.md

1.2 操作步骤(一条命令一步,看现象)

实测环境是在代码/目录下(脚本里的路径指向各课时目录);同学们按自己的目录改路径即可。

第 0 步:先把"总机"和网关程序准备好

pgrep-xubusd>/dev/null||sudoubusd&# ubus 总机(课时 31 用过)ls~/lab/课时31-网关产品化uci与ubus/gateway_pro# 网关程序(课时 32 守护的就是它)uci show device|head-3# 配置在位

第 1 步:★跑一键验收(约 1~2 分钟)

cd~/lab/课时33-项目验收sudo./acceptance.sh# 想快点:./acceptance.sh --quick(跳过完整故障注入)

现象(实测,27 项全通过、0 失败):

================ 模块七 综合项目 验收 ================ 时间:2026-09-26 06:04:04 【① 环境检查】 [通过] socat 已安装 [通过] libubox 头文件在位 [通过] libubus 头文件在位 [通过] Flask 可用 [通过] pyserial 可用 [通过] uci / ubus 可用 [通过] systemd 可用 【② 建立虚拟串口】 [通过] 虚拟串口 /tmp/ttyV0 <-> /tmp/ttyV1 已建立 【③ 设备面板 + 网关】 [通过] 设备面板在发 0x80 状态帧 [通过] 网关已启动(配置读 /etc/config/device) [通过] 网关认到了设备(状态表已建立) 【④ 网关状态查询(ubus)】 [通过] ubus call device status 有返回 [通过] online = 1(设备在线) [通过] ser_rx = 3(串口确实收到过帧) 【⑤ 状态上报(每 2 秒 0x81)】 [通过] 监听端 5 秒内收到 3 帧 0x81 上报 收到 55 AA 81 05 00 00 00 F7 01 0D AD → 灯 灭 | 风扇 0 档 | 24.7 ℃ | 在线 【⑥ 网页上位机(显示 + 控制)】 [通过] /api/state 显示设备在线 [通过] 网页按钮控制成功(led=1 fan=2) 【⑦ 设备掉线判定与恢复】 [通过] 设备掉线后 online 变成 0 [通过] 设备回来后 online 自动恢复成 1 【⑧ 故障注入(坏帧不影响正常工作)】 [通过] 网关识别并丢弃了坏 CRC 帧 [通过] 故障注入后网关照常收帧(ser_rx 25 → 50) [通过] 故障注入后设备仍在线 【⑨ systemd 守护与自愈】 [通过] 服务已启动(systemctl is-active = active) [通过] kill -9 后服务被自动拉起(active) [通过] 重启次数 NRestarts = 2 [通过] 服务已卸载(现场恢复干净) 【⑩ 清理现场】 [通过] 所有进程已停止,端口已释放 ================ 验收结果 ================ 通过:27 项 失败:0 项 结论:模块七 综合项目 验收通过 ✓

第 2 步:按《验收清单》给自己打分

less~/lab/课时33-项目验收/验收清单.md

逐条对照,把"A 功能 60 / B 健壮性 20 / C 工程化 12 / D 交付答辩 8"填完。
acceptance.sh覆盖了其中绝大部分可自动化的项,剩下的(代码整洁、README、答辩)由老师和同学互评。

第 3 步:★换一个终端/新环境再跑一遍(真正的验收)

# 换一个干净终端,或者在新克隆的目录里,按 README 从头跑一遍cd~/lab/课时33-项目验收sudo./acceptance.sh

这一步的意义:证明你的项目不是"只能在你机器上跑"。
常见翻车点:路径写死、忘了装某个包、忘了uci commit、忘了起ubusd。

第 4 步:答辩演练(5 分钟掐表)

less~/lab/课时33-项目验收/答辩提纲.md

按提纲的四段做一遍:① 架构图 1 分钟 → ② 主流程演示 2 分钟 → ③ 掉线 + 自愈 1 分钟 → ④ 坑与收获 1 分钟。
再让同桌随机问"12 个常问问题"里的 3 个,答不上来的回去补。

第 5 步:收工。脚本已自动清理(进程/端口/服务都还原);ubusd可留可停(sudo pkill -x ubusd)。

1.3 常见错误与排查

现象原因解决
④ 报ubus 查询没返回ubusd 没启动sudo ubusd &;或ls -l /var/run/ubus/ubus.sock确认
③ 报设备面板没有发帧面板没起来(PyQt/Xvfb 问题)看/tmp/acc_panel.log;无桌面时用xvfb-run python3 device_panel_serial.py
③ 报网关没起来9000 端口被占 / 串口打不开ss -ltnp | grep 9000杀掉旧进程;确认 socat 起了
⑤ 报5 秒内没收到上报网关的上报目标不是127.0.0.1:9100看/tmp/acc_gw.log的启动行;或uci show device | grep report
⑥ 报/api/state 不对5000 被占 / 网页没起来看/tmp/acc_app.log;ss -ltnp | grep 5000
⑦ 掉线判不出来offline_ms配得太大uci set device.main.offline_ms=3000 && uci commit device后重启网关
⑨ 服务 self-heal 失败systemd 不可用(容器里常见)用虚拟机跑;或在真机上确认 PID 1 是 systemd
脚本跑完端口还被占上一次跑挂了没清理pkill -f gateway_pro; pkill -x socat,或重启虚拟机
全部失败但手工跑却正常目录不对(脚本找各课时目录找错了)脚本用$0自动算出C26/C29/C30/C31/C32(从"脚本所在目录"往上两层取代码/),仓库 clone 或解压到哪都能跑;只有你把某个课时目录搬走时才需要改开头的这几行

二、学生练习

本节命令速查表:

命令作用示例
sudo ./acceptance.sh一键端到端验收(十项 27 检查点)--quick快跑
sudo ubusd &起 ubus 总机(④ 需要)早已在课时 31 做过
less 验收清单.md/less 答辩提纲.md自评 / 演练边看边填
exit $FAIL式的脚本骨架自己写检查脚本见 1.1 的ok/bad
编号任务提示预期结果
L33.1跑通acceptance.sh第 1 步27 项全通过
L33.2故意制造一处失败改offline_ms为 60000 再跑⑦ 报失败,学会"看哪项红了"
L33.3给脚本加一个新检查点例如检查/etc/config/device里的report_ms与网关启动行一致脚本变 28 项
L33.4写自己的 README别人照着能跑通(含依赖、步骤、现象)同桌按它跑一遍不出错
L33.5按清单自评逐项填"自测"列分数 ≥ 85
L33.6答辩演练掐表 5 分钟 + 随机抽 3 问讲解流利、问题能答

三、作业(模块七项目交付物)

必交(按此清单打包,命名学号-姓名-模块七项目/):

#交付物要求
1代码课时 24~32 你写/改过的文件;gcc -Wall -Wextra零警告
2README.md依赖清单、编译命令、运行步骤(几个终端分别跑什么)、预期现象、常见问题
3协议契约.md帧格式、CRC、类型表(可沿用课时 24 的版本,改动要更新)
4验收截图/记录acceptance.sh的完整输出(27 项)+ 网页界面截图 + 掉线/自愈各一张
5《验收清单》自评表逐项打分并写一句依据
6答辩提纲按模板填自己的架构图与两个"坑"

思考题(写在 README 末尾):

  1. 验收脚本里哪几项是"功能"、哪几项是"健壮性"、哪几项是"工程化"?为什么验收要三者都覆盖?
  2. 如果要把这个项目搬到真实硬件(设备换成单片机 + 真串口,网关跑在 ARM 开发板上),你需要改哪些地方?(提示:串口路径、交叉编译、systemd、网络)
  3. 这个项目里哪一处最脆弱?如果要再加一道保险,你会加什么?

四、模块七小结(把整条链路再走一遍)

①设备面板(PyQt5) ②网关(C, uloop) ③上位机(Flask 网页) ┌───────────────┐ 串口 ┌──────────────────────┐ TCP命令 ┌──────────────┐ │ 灯/风扇/温度 │ 55AA帧 │ 四道防线:帧头→LEN→CRC │◀────────│ 按钮(表单) │ │ 0x80 每秒上报 │ ─────▶ │ →类型 │ │ │ │ 收命令改状态 │ ◀───── │ 状态表(灯/风扇/温度/在线)│ UDP上报 │ 页面显示状态 │ └───────────────┘ │ 0x81 每 2 秒上报 │ ──────▶ │ /api/state │ │ 配置读 uci、状态走 ubus │ 0x81 └──────────────┘ └──────────────────────┘ ↑ systemd 守护(挂了自动起)
  • 协议:55 AA | TYPE | LEN | PAYLOAD | CRC16(低字节在前);TCP 外加 2 字节大端长度前缀
  • 职责划分:设备只管"状态 + 执行命令";网关管"转帧 + 记状态 + 判在线 + 对外提供接口";上位机管"显示 + 控制"
  • 工程化三件套:配置外置(uci)、状态可查(ubus)、崩溃自愈(systemd)
  • 可靠性三件套:帧同步 + CRC 校验(坏数据不进门)、缓冲区上限(不被灌爆)、在线判定(失联能发现)

全课程回头看:模块一~六(Ubuntu 基础、C 语言与结构体、进程与服务、网络编程、uloop 事件驱动、uci/ubus/JSON),到这里都变成了一个能演示的项目里的一颗螺丝钉——这就是"嵌入式 Linux 应用开发"的完整套路。

继续往哪走(选修/毕设方向):① 换成真实传感器(DHT11/DS18B20)与真串口;② 用 SQLite 存历史数据 + 画曲线;③ 用 MQTT 把状态发给云平台;④ 交叉编译到 ARM 开发板(课时 16 起的库要在板子上重新编);⑤ 给网页加登录与权限。


附录:怎么运行 + 脚本关键代码

三个文件在代码/课时33-项目验收/:acceptance.sh(一键验收,十项 27 检查点)、验收清单.md(100 分自评表)、答辩提纲.md(5 分钟讲解 + 12 问)。

附录 A|完整跑一遍(含前置依赖)

# ===== ⓿ 前置:课时 24~32 的环境与程序都就位 =====sudoaptinstall-ysocat python3-pyqt5 python3-serial python3-flask xvfbls/usr/local/lib/libuci.so /usr/local/lib/libubus.so# 课时 15 编的ls~/lab/课时31-网关产品化uci与ubus/gateway_pro# 课时 31 编的uci show device|head-3# 课时 31 装的配置# ===== ① 起 ubus 总机(验收第 ④ 项要用)=====sudoubusd&# ===== ② 一键验收 =====cd~/lab/课时33-项目验收sudo./acceptance.sh# 约 1~2 分钟;--quick 可跳过完整故障注入# ===== ③ 看结果 =====# 通过:27 项 失败:0 项# 结论:模块七 综合项目 验收通过 ✓# ===== ④ 自评 + 答辩演练 =====less验收清单.mdless答辩提纲.md

acceptance.sh开头的C26/C29/C30/C31/C32按脚本自身位置算(脚本在代码/课时33-项目验收/,往上两层就是代码/),所以整仓库 clone / 解压到任何目录都能直接跑,不用改路径。另外,仓库里不带 C 编译产物:首次运行脚本会自动用 gcc 编译课时 31 的gateway_pro(编过了就跳过),所以第 ⓿ 步不手工编译也能跑。

附录 B|acceptance.sh的关键写法

B-1 计数与打印(整个脚本的骨架)

PASS=0FAIL=0ok(){echo" [通过]$1";PASS=$((PASS+1));}bad(){echo" [失败]$1";FAIL=$((FAIL+1));}# 单项检查:条件成立就"通过",否则"失败"[-f/usr/local/include/libubus.h]&&ok"libubus 头文件在位"||bad"缺 libubus(回课时 15)"

B-2 把"现象"变成"可判断的条件"

# 环境是否齐全command-vsocat>/dev/null&&ok"socat 已安装"||bad"socat 未安装"# 设备帧是否真的在发(读面板日志)grep-aq'发送 0x80'/tmp/acc_panel.log&&ok"设备面板在发 0x80 状态帧"||bad"设备面板没有发帧"# 状态表是否正确(从 ubus 的 JSON 里抠字段)STATUS="$(ubus call device status2>/dev/null)"echo"$STATUS"|grep-q'"online": 1'&&ok"online = 1(设备在线)"||bad"online 不是 1"RX="$(echo"$STATUS"|grep-o'"ser_rx": [0-9]*'|grep-o'[0-9]*')"["${RX:-0}"-gt0]&&ok"ser_rx =$RX(串口确实收到过帧)"||bad"ser_rx = 0"

B-3 主动"做动作"再检查(掉线、自愈)

# 掉线:杀掉设备 → 等 6 秒 → 看 online 是否变 0pkill-f'device_panel_seria[l]'sleep6OFF="$(wget-qO- http://127.0.0.1:5000/api/state|grep-o'"online":[0-9]*'|grep-o'[0-9]*')"["${OFF:-1}"="0"]&&ok"设备掉线后 online 变成 0"||bad"掉线没判出来(online=$OFF)"# 自愈:kill -9 → 等 5 秒 → 服务还在 active 且 NRestarts ≥ 1PID1="$(systemctl show-pMainPID--valuedevice-gateway)"kill-9"$PID1"sleep5["$(systemctl is-active device-gateway)"="active"]&&ok"kill -9 后服务被自动拉起"||bad"自愈失败"NR="$(systemctl show-pNRestarts--valuedevice-gateway)"["${NR:-0}"-ge1]&&ok"重启次数 NRestarts =$NR"||bad"NRestarts =$NR"

B-4 收尾一定要清理(trap保证异常退出也清理)

cleanup_all(){[-n"${APP:-}"]&&kill$APP2>/dev/null[-n"${LISTEN:-}"]&&kill$LISTEN2>/dev/null[-n"${GW:-}"]&&kill$GW2>/dev/nullpkill-f'device_panel_seria[l]'2>/dev/null"$C32/install_service.sh"--uninstall>/dev/null2>&1pkill-xsocat2>/dev/nullsleep1}trapcleanup_all EXIT

导出结论:exit 0(全通过)/exit 1(有失败)—— 这样以后放进 CI(比如 gitee 的流水线)也能用。

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

五大云厂商大模型广场横评:价格双协议与迁移成本全对比2026

大模型API聚合平台是近两年崛起的基础设施新品类&#xff1a;把多家厂商的推理能力统一成标准接口&#xff0c;一个Key加一个接口地址就能在模型间切换&#xff0c;代码只改一行。它的三大价值是接口统一、模型灵活、成本可控。本文横向对比七牛云AI、硅基流动、阿里百炼、百度…

作者头像 李华
网站建设 2026/10/3 12:37:53

关于C语言的基础知识点

前言 C语言是其他语言的发展初始阶段&#xff0c;这里介绍了关于C语言的基础知识点&#xff0c;以便于后面的运用 基础知识点 必记&#xff1a;写代码必须加头文件 #include<stdio.h> 1.主函数 int main( ){ return 0; } 注意&#xff1a;return 0表示程序成功执行完毕 r…

作者头像 李华
网站建设 2026/10/3 12:34:59

涂料厂巡检怎么做?树脂车间、调漆间与成品库三处

涂料厂的隐患有一条很清晰的主线&#xff1a;溶剂。涂料、稀释剂、固化剂里普遍含有易燃有机溶剂&#xff0c;挥发出来的蒸气比空气重、闪点低&#xff0c;而生产与灌装环节又大量存在静电、搅拌与搬运。理解这条主线&#xff0c;三处重点就都能串起来了。 树脂车间与分散研磨…

作者头像 李华
网站建设 2026/10/3 12:34:03

python学习day09——异常

1.异常介绍1.1 语法错误&#xff08;Error&#xff09;代码写错了&#xff0c;程序根本跑不起来。# 语法错误&#xff0c;少了冒号if 5>3print("ok")常见语法错误&#xff1a;SyntaxError、缩进错误 IndentationError语法错误必须改代码&#xff0c;无法用异常捕获…

作者头像 李华