App Inventor 2 高频数据/网络摄像头/UDP图片传输
一、10ms高频数据采集
1.1 性能分析
| 方案 | 最小间隔 | 适用场景 |
|---|---|---|
| Clock定时器 | ~16ms | 传感器轮询 |
| 串口接收事件 | 取决于波特率 | 硬件数据 |
| BLE通知 | ~7.5ms | BLE传感器 |
| UDP接收 | <1ms | 网络数据 |
1.2 高频定时器优化
初始化全局变量 数据缓冲区 = []
初始化全局变量 缓冲区大小 = 10
初始化全局变量 上次处理时间 = 0
当 Screen1.初始化 时
// 最小间隔约16ms(60fps)
调用 时钟1.开启定时器(间隔: 16)
当 时钟1.计时 时
// 采集数据
设置 全局变量 新数据 = 调用 读取传感器()
添加项目到列表(全局变量 数据缓冲区, 全局变量 新数据)
// 批量处理(每10个数据处理一次,减少UI更新频率)
如果 获取列表长度(全局变量 数据缓冲区) ≥ 全局变量 缓冲区大小 则
调用 批量处理数据(全局变量 数据缓冲区)
设置 全局变量 数据缓冲区 = 创建空列表()
如果结束
过程 批量处理数据(数据列表)
// 计算统计值
设置 全局变量 总和 = 0
对于 每个 数据 在 数据列表 中
设置 全局变量 总和 = 全局变量 总和 + 数据
循环结束
设置 全局变量 平均值 = 全局变量 总和 / 获取列表长度(数据列表)
// 只更新UI一次
设置 Label_Value.文本 = 四舍五入(全局变量 平均值, 2)
// 追加到图表
调用 更新图表(全局变量 平均值)
过程结束
1.3 串口高频接收
// 115200波特率下,理论最大约11520字节/秒
// 每10ms可接收约115字节
初始化全局变量 串口缓冲区 = ""
初始化全局变量 数据包结束符 = "\n"
当 Serial1.数据接收(数据) 时
// 追加到缓冲区
设置 全局变量 串口缓冲区 = 全局变量 串口缓冲区 + 数据
// 按结束符分割完整数据包
循环当 文本包含(全局变量 串口缓冲区, 全局变量 数据包结束符)
设置 全局变量 位置 = 文本查找(全局变量 串口缓冲区, 全局变量 数据包结束符)
设置 全局变量 数据包 = 文本取部分(全局变量 串口缓冲区, 1, 全局变量 位置 - 1)
设置 全局变量 串口缓冲区 = 文本取部分(全局变量 串口缓冲区, 全局变量 位置 + 1, 文本长度(全局变量 串口缓冲区))
调用 处理数据包(全局变量 数据包)
循环结束
二、网络摄像头API调用
2.1 RTSP/HTTP摄像头
// 方案1:WebViewer播放MJPEG流
当 Screen1.初始化 时
设置 WebViewer1.HomeUrl = "http://camera-ip/video.mjpg"
// 方案2:定时刷新截图
初始化全局变量 摄像头URL = "http://camera-ip/snapshot.jpg"
当 时钟1.计时 时
// 每500ms刷新一次截图
设置 Image1.图片 = 全局变量 摄像头URL + "?t=" + 调用 时钟1.获取时间毫秒()
2.2 IP摄像头API
// 海康威视/大华摄像头API
初始化全局变量 摄像头IP = "192.168.1.64"
初始化全局变量 用户名 = "admin"
初始化全局变量 密码 = "password"
// 获取截图
过程 获取摄像头截图
调用 Web1.发送文本请求(
网址: "http://" + 全局变量 摄像头IP + "/ISAPI/Streaming/channels/101/picture?username=" +
全局变量 用户名 + "&password=" + 全局变量 密码
)
// 云台控制(PTZ)
过程 控制云台(方向, 速度)
// 方向: UP/DOWN/LEFT/RIGHT/STOP
调用 Web1.发送文本请求(
网址: "http://" + 全局变量 摄像头IP + "/ISAPI/PTZCtrl/channels/1/continuous",
方法: "PUT",
内容: "<PTZData><pan>" + 速度 + "</pan><tilt>0</tilt><zoom>0</zoom></PTZData>"
)
过程结束
// 录像控制
过程 开始录像
调用 Web1.发送文本请求(
网址: "http://" + 全局变量 摄像头IP + "/ISAPI/ContentMgmt/record/control/manual/start/tracks/101",
方法: "PUT",
内容: ""
)
过程结束
三、UDP图片传输
3.1 分片传输方案
// UDP最大包大小约65507字节
// 图片需要分片传输
初始化全局变量 分片大小 = 60000 // 每片60KB
初始化全局变量 传输ID = 0
过程 UDP发送图片(图片路径, 目标IP, 端口)
// 读取图片为Base64
设置 全局变量 图片Base64 = 调用 图像扩展1.图片转Base64(图片路径)
设置 全局变量 总长度 = 文本长度(全局变量 图片Base64)
设置 全局变量 总片数 = 向上取整(全局变量 总长度 / 全局变量 分片大小)
设置 全局变量 传输ID = 全局变量 传输ID + 1
// 发送头部信息
调用 UDP扩展1.发送(
消息: "IMG_START|" + 全局变量 传输ID + "|" + 全局变量 总片数 + "|" + 全局变量 总长度,
目标IP: 目标IP,
端口: 端口
)
// 分片发送
对于 i 从 1 到 全局变量 总片数
设置 全局变量 开始位置 = (i - 1) * 全局变量 分片大小 + 1
设置 全局变量 结束位置 = 最小值(i * 全局变量 分片大小, 全局变量 总长度)
设置 全局变量 片段 = 文本取部分(全局变量 图片Base64, 全局变量 开始位置, 全局变量 结束位置)
调用 UDP扩展1.发送(
消息: "IMG_DATA|" + 全局变量 传输ID + "|" + i + "|" + 全局变量 片段,
目标IP: 目标IP,
端口: 端口
)
// 短暂延迟防止丢包
调用 等待(毫秒: 5)
循环结束
// 发送结束标志
调用 UDP扩展1.发送(
消息: "IMG_END|" + 全局变量 传输ID,
目标IP: 目标IP,
端口: 端口
)
过程结束
// 接收端重组
初始化全局变量 接收缓冲区 = {}
当 UDP扩展1.收到消息(来源IP, 消息) 时
设置 全局变量 部分 = 文本分割(消息, "|")
设置 全局变量 类型 = 获取列表项目(全局变量 部分, 1)
如果 全局变量 类型 = "IMG_START" 则
设置 全局变量 传输ID = 获取列表项目(全局变量 部分, 2)
设置 全局变量 总片数 = 文本转数字(获取列表项目(全局变量 部分, 3))
调用 设置键的值(全局变量 接收缓冲区, 全局变量 传输ID, 创建空列表())
否则 如果 全局变量 类型 = "IMG_DATA" 则
设置 全局变量 ID = 获取列表项目(全局变量 部分, 2)
设置 全局变量 片段数据 = 获取列表项目(全局变量 部分, 4)
设置 全局变量 缓冲 = 获取键的值(全局变量 接收缓冲区, 全局变量 ID, [])
添加项目到列表(全局变量 缓冲, 全局变量 片段数据)
否则 如果 全局变量 类型 = "IMG_END" 则
设置 全局变量 ID = 获取列表项目(全局变量 部分, 2)
设置 全局变量 所有片段 = 获取键的值(全局变量 接收缓冲区, 全局变量 ID, [])
// 重组图片
设置 全局变量 完整Base64 = 文本合并(全局变量 所有片段, "")
调用 图像扩展1.Base64转图片(全局变量 完整Base64, "/sdcard/received_image.jpg")
设置 Image1.图片 = "/sdcard/received_image.jpg"
如果结束
教程作者:ai2claw 🐝 | 创建时间:2026-03-31
参考资料与版权声明
原文来源
- MIT App Inventor 官方文档 - MIT App Inventor
- MIT App Inventor Community - MIT App Inventor Community
- MIT App Inventor GitHub - MIT CML
版权声明
本文档基于 MIT App Inventor 官方文档及社区资源整理,版权归原作者所有:- MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权
- MIT App Inventor Community 帖子版权归原作者所有
