1. 数据采集项目概述
"day2-采集数据"这个标题看似简单,实际上涵盖了数据采集领域的核心工作流程。作为一名在工业自动化和物联网领域摸爬滚打多年的工程师,我处理过从简单的传感器数据采集到复杂的分布式系统监控等各种场景。数据采集作为任何监控系统或自动化项目的第一步,其重要性怎么强调都不为过——垃圾数据进,垃圾分析出,后续所有工作都建立在可靠的数据采集基础上。
这个项目主要涉及三种典型场景:Linux系统监控(特别是进程和CPU数据)、网页端的性能指标检测、以及嵌入式系统(如STM32)的传感器数据采集与电机控制。这三种场景恰好覆盖了从软件到硬件的完整数据采集谱系,也是目前工业界最常见的应用组合。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据采集系统设计思路
2.1 架构设计考量
在设计数据采集系统时,我通常会考虑三个关键维度:采样频率、数据精度和系统可靠性。对于Linux进程监控,采样间隔可能需要秒级甚至毫秒级;而STM32的传感器采集则可能根据传感器特性需要微秒级响应。网页端的CPU监测则更关注长时间运行的稳定性。
我推荐的分层架构如下:
- 采集层:负责原始数据获取(如top命令、ADC读取)
- 传输层:数据缓存和传输(内存队列、MQTT等)
- 持久层:数据存储(数据库、文件系统)
- 展示层:可视化界面(网页、移动端)
2.2 技术选型分析
针对不同场景,工具链选择差异很大:
- Linux系统监控:bash/python脚本+time序列数据库(如InfluxDB)
- 网页检测:JavaScript Performance API+WebSocket
- STM32开发:HAL库+CubeMX配置
特别提醒:在嵌入式开发中,ADC采样频率和DMA配置直接影响数据质量。我曾在一个电机控制项目中,因为ADC时钟配置错误导致采样值抖动严重,花了三天才排查出这个隐蔽问题。
3. Linux系统监控实现细节
3.1 进程数据采集实战
采集top数据最可靠的方式是直接解析/proc文件系统。这是我用了多年的bash脚本片段:
bash复制#!/bin/bash
while true; do
timestamp=$(date +%s)
cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
mem_usage=$(free -m | awk '/Mem:/ {print $3/$2 * 100.0}')
echo "$timestamp,$cpu_usage,$mem_usage" >> system_metrics.csv
sleep 5
done
关键技巧:
- 使用
-bn1参数让top只运行一次 - 通过100减去idle百分比得到CPU使用率
- 时间戳采用Unix epoch格式方便后续处理
3.2 数据处理与告警
原始数据需要经过滑动窗口计算才能得到有意义的均值和峰值。Python的pandas库非常适合这种处理:
python复制import pandas as pd
df = pd.read_csv('system_metrics.csv', names=['timestamp','cpu','mem'])
df['5min_avg'] = df['cpu'].rolling(window=12).mean() # 5分钟均值(12个5秒样本)
df['30min_peak'] = df['cpu'].rolling(window=360).max() # 30分钟峰值
重要提示:在生产环境中务必添加异常值过滤,我曾遇到因为瞬间IO飙升导致CPU读数突破100%的情况,这种异常点会严重扭曲统计结果。
4. 网页端CPU监控实现
4.1 浏览器端数据采集
现代浏览器提供了强大的Performance API,可以获取精确到毫秒的性能数据:
javascript复制// 获取CPU使用率
function getCPUUsage() {
const startTime = performance.now();
const startUsage = process.cpuUsage(); // Node.js环境
// 模拟工作负载
for(let i=0; i<1000000; i++) Math.random();
const endUsage = process.cpuUsage(startUsage);
const endTime = performance.now();
const elapsedTime = endTime - startTime;
const cpuPercent = (endUsage.user + endUsage.system) / (elapsedTime * 1000) * 100;
return cpuPercent;
}
4.2 数据可视化方案
我推荐使用ECharts实现实时曲线展示,其双缓冲机制能流畅处理高频更新:
javascript复制const chart = echarts.init(document.getElementById('chart'));
let data = [];
setInterval(() => {
const usage = getCPUUsage();
data.push({
time: new Date().toLocaleTimeString(),
value: usage
});
if(data.length > 60) data.shift(); // 保持最近60个点
chart.setOption({
series: [{
data: data.map(item => item.value)
}]
});
}, 1000);
5. STM32数据采集与电机控制
5.1 传感器数据采集
使用STM32CubeMX配置ADC采集光照传感器数据的典型流程:
- 在CubeMX中启用ADC1,选择对应通道
- 设置采样时间为239.5个时钟周期(平衡速度和精度)
- 启用DMA循环模式实现不间断采集
- 生成代码后添加数据处理逻辑:
c复制#define SAMPLE_COUNT 64
uint32_t adc_buffer[SAMPLE_COUNT];
float get_sensor_avg() {
uint32_t sum = 0;
for(int i=0; i<SAMPLE_COUNT; i++) {
sum += adc_buffer[i];
}
return (sum * 3.3) / (SAMPLE_COUNT * 4095); // 转换为电压值
}
5.2 直流电机PID控制
电机控制需要结合传感器反馈形成闭环。这是我验证过的PID实现:
c复制typedef struct {
float Kp, Ki, Kd;
float integral, prev_error;
} PIDController;
float pid_update(PIDController* pid, float setpoint, float measurement) {
float error = setpoint - measurement;
pid->integral += error * 0.01f; // 假设采样周期10ms
pid->integral = constrain(pid->integral, -100, 100); // 抗积分饱和
float derivative = (error - pid->prev_error) / 0.01f;
pid->prev_error = error;
return pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;
}
电机控制经验:PWM频率建议选择10-20kHz,既能避免可闻噪声,又不会导致MOS管过热。我曾因为使用5kHz频率导致电机发出刺耳的啸叫声。
6. 系统集成与问题排查
6.1 数据同步挑战
当多个采集终端向中央服务器发送数据时,时钟同步至关重要。我推荐采用NTP协议进行时间同步,对于要求更高的场景,可以使用PTP(IEEE 1588)协议。
在Linux上配置NTP客户端:
bash复制sudo apt install chrony
sudo systemctl enable chronyd
对于STM32,可以通过GPS模块或从网络包中提取时间戳。
6.2 常见故障排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| Linux CPU读数异常高 | 瞬间IO负载 | 增加采样间隔或使用1分钟负载平均值 |
| 网页端数据延迟 | WebSocket连接中断 | 实现心跳机制和自动重连 |
| STM32 ADC值跳动 | 电源噪声 | 添加LC滤波电路,使用软件均值滤波 |
| 电机控制振荡 | PID参数不当 | 先调P,再调D,最后调I |
6.3 数据完整性保障
在分布式采集系统中,我通常会采用以下策略确保数据可靠:
- 本地缓存:每个采集节点维护一个环形缓冲区
- 断点续传:记录最后成功发送的时间戳
- 数据校验:添加CRC校验或哈希值
- 幂等设计:服务端能够处理重复数据
这是我使用的Python数据发送重试逻辑:
python复制def send_with_retry(data, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.post('http://server/api/data', json=data, timeout=5)
if response.status_code == 200:
return True
except Exception as e:
print(f"Attempt {attempt+1} failed: {str(e)}")
time.sleep(2 ** attempt) # 指数退避
return False
7. 性能优化技巧
经过多个项目的积累,我总结出这些提升采集系统性能的关键点:
-
Linux系统监控优化:
- 使用
/proc/stat代替top命令减少开销 - 采用eBPF技术实现内核级监控
- 考虑使用sysdig等专业工具
- 使用
-
网页端优化:
- 使用Web Worker处理计算密集型任务
- 采用二进制协议(如Protocol Buffers)减少传输量
- 实现数据分级(原始数据、分钟级、小时级)
-
嵌入式优化:
- 启用ADC过采样提升有效位数
- 使用定时器触发ADC实现精确间隔采样
- DMA双缓冲技术实现无停顿采集
以STM32的ADC过采样为例,通过16倍过采样可以将12位ADC提升到14位有效分辨率:
c复制// 在CubeMX中配置
hadc1.Init.OversamplingMode = ENABLE;
hadc1.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_16;
hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_2;
hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
8. 项目演进方向
这个数据采集系统可以沿着多个方向扩展:
-
边缘计算:在采集端增加预处理能力,比如:
- 异常检测算法(如3σ原则)
- 数据压缩(如delta编码)
- 特征提取(FFT分析)
-
多协议支持:
- 工业协议(Modbus, OPC UA)
- 物联网协议(MQTT, CoAP)
- 传统协议(SNMP)
-
AI集成:
- 使用LSTM预测趋势
- 聚类分析识别异常模式
- 强化学习优化控制参数
我曾在一个预测性维护项目中,通过在边缘设备运行轻量级LSTM模型,成功将异常检测延迟从秒级降低到毫秒级。关键是在STM32上使用CMSIS-NN库实现神经网络推理:
c复制#include "arm_nnfunctions.h"
void run_lstm(const q7_t* input, q7_t* output) {
arm_rnn_single_step_s8(
&lstm_context, // 预训练好的模型参数
&lstm_conf, // 网络配置
input, // 输入数据
output // 预测结果
);
}
数据采集系统就像项目的眼睛和耳朵,只有获得准确、及时的数据,后续的分析和控制才有意义。在实际实施中,我建议采用迭代开发的方式:先建立最小可用的采集框架,然后逐步添加数据处理、传输、存储和展示功能。记住,一个好的采集系统应该像优秀的助手一样,既不会遗漏重要信息,也不会用无关细节淹没使用者。
