高实时性远程传感器数据采集
硬件配置
- 主站: Windows 10 × 1 + Intel i3 × 1
- 称重变送器: EtherCAT 称重模块 × 15 (分布在厂区不同料仓)
- 网络拓扑: 菊花链,可分支,节点间最远 80m
成本分析
| 类别 | 型号/规格 | 参考单价 (¥) | 数量 | 小计 (¥) |
|---|---|---|---|---|
| 称重变送器 | EtherCAT 称重模块 | 600 | 15 | 9,000 |
| 工控机 | Intel i3 级别 | 2,500 | 1 | 2,500 |
| 整线参考总计 | ≈ ¥11,500 |
以上为核心部件参考价 (RMB),不含称重传感器、线缆等。
性能指标
- 采样周期: 250 µs
- 称重精度: ±0.1%
- 传输距离: 节点间最远 80m
- 采集通道: 15 路 (每模块 4 通道, 本示例仅用 1 通道)
应用场景
化工原料料仓管理系统。
15 个称重变送器分布在厂区不同料仓(节点间最远 80m),主站以 250µs 周期实时采集重量数据。
本示例作为数据采集层,外部系统直接访问 Weights[] 属性获取实时重量,实现库存监控、自动补料、超限告警等业务逻辑。
实际运用往往是系统主动高速采集。
也可用于多点温度/压力/流量等传感器的高速同步采集场景。
代码示例
PDO 结构体定义 (4 通道模块, 本示例仅用 1 通道)
using System.Runtime.InteropServices;
/// <summary>
/// 4通道称重变送器输入 PDO (0x6000)
/// 每个子索引为一个通道的重量值, 只读
/// 本示例仅使用 W1 (1通道)
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct WeighingModule_Input
{
public int W1; // 0x6000:01 - 1通道重量值 (本示例使用)
public int W2; // 0x6000:02 - 2通道重量值
public int W3; // 0x6000:03 - 3通道重量值
public int W4; // 0x6000:04 - 4通道重量值
}
/// <summary>
/// 4通道称重变送器输出 PDO (0x7000)
/// 标定命令: 写1=标零, 写4=清零, 写16=确认无砝码标定, 写>100=标增益
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct WeighingModule_Output
{
public int Calibration1; // 0x7000:01 - 1通道标定
public int Calibration2; // 0x7000:02 - 2通道标定
public int Calibration3; // 0x7000:03 - 3通道标定
public int Calibration4; // 0x7000:04 - 4通道标定
public int FullScale; // 0x7000:05 - 满量程
public int Sensitivity; // 0x7000:06 - 灵敏度 (实际值×10000, 如2.0mv/V写20000)
}
控制代码
using System;
using System.Threading;
using DarraEtherCAT_Master;
class WeighingController
{
// ============ 可配置参数 (外部设置) ============
/// <summary> 称重模块数量 </summary>
public static int ModuleCount { get; set; } = 15;
// ============ 采集数据 (外部系统直接读取) ============
/// <summary>
/// 所有料仓实时重量 (每模块仅用 W1), 外部系统直接访问此属性
/// </summary>
public static int[] Weights { get; set; } = new int[15];
/// <summary>
/// 采样计数, 外部系统可据此判断数据是否刷新
/// </summary>
public static volatile long SampleCount;
static void Main(string[] args)
{
var master = new DarraEtherCAT()
.LoadENI("config/sensor_acquisition.xml")
.Build();
if (master == null)
{
Console.WriteLine("主站初始化失败!");
return;
}
try
{
var (success, msg) = master.SetState(EcState.OP);
if (!success)
{
Console.WriteLine($"无法进入 OP 状态: {msg}");
return;
}
int slaveCount = Math.Min(ModuleCount, master.Slaves.Count);
Console.WriteLine($"传感器采集启动! 在线模块: {slaveCount}/{ModuleCount}");
// 映射只需获取一次, 引用指向共享PDO内存, 循环内直接读取即可
// 因为从站数量动态, 使用 unsafe 指针数组缓存映射地址
unsafe
{
// 预获取所有模块的输入PDO指针
WeighingModule_Input*[] inputs = new WeighingModule_Input*[slaveCount];
for (int i = 0; i < slaveCount; i++)
fixed (WeighingModule_Input* p = &master.Slaves[i].InputsMapping<WeighingModule_Input>())
inputs[i] = p;
while (true)
{
// 遍历所有称重模块, 仅读取 W1 (1通道)
for (int i = 0; i < slaveCount; i++)
Weights[i] = inputs[i]->W1;
SampleCount++;
Thread.Sleep(0);
}
}
}
finally
{
master.Dispose();
}
}
// ============ 外部系统调用接口 ============
/// <summary>
/// 获取指定料仓重量 (外部系统直接调用)
/// </summary>
public static int GetWeight(int moduleIndex) => Weights[moduleIndex];
// ============ 标定流程 ============
//
// 有砝码标定 (推荐):
// 1. 空载 → TareZero() 清零
// 2. 放上已知砝码 → CalibrateGain(砝码重量) 标定增益
//
// 无砝码标定:
// 1. SetCalibrationParams(灵敏度, 满量程) 写入传感器参数
// 2. 空载 → TareZero() 清零
// 3. ConfirmNoWeightCalibration() 确认无砝码标定
/// <summary>
/// 步骤1: 空载清零 (秤台上无物料时调用)
/// </summary>
public static void TareZero(DarraEtherCAT master, int moduleIndex)
{
ref var output = ref master.Slaves[moduleIndex].OutputsMapping<WeighingModule_Output>();
output.Calibration1 = 1; // 1=标零
}
/// <summary>
/// 步骤2: 放上已知砝码后标定增益 (写入砝码实际重量值, 必须>100)
/// </summary>
/// <param name="knownWeight">砝码重量值 (必须>100, 如5000g写5000)</param>
public static void CalibrateGain(DarraEtherCAT master, int moduleIndex, int knownWeight)
{
ref var output = ref master.Slaves[moduleIndex].OutputsMapping<WeighingModule_Output>();
output.Calibration1 = knownWeight; // >100=标增益
}
/// <summary>
/// 无砝码标定: 写入传感器参数 (需在清零前调用)
/// </summary>
/// <param name="sensitivity">传感器灵敏度 (实际值×10000, 如2.0mV/V写20000)</param>
/// <param name="fullScale">满量程值</param>
public static void SetCalibrationParams(DarraEtherCAT master, int moduleIndex, int sensitivity, int fullScale)
{
ref var output = ref master.Slaves[moduleIndex].OutputsMapping<WeighingModule_Output>();
output.Sensitivity = sensitivity;
output.FullScale = fullScale;
}
/// <summary>
/// 无砝码标定: 确认 (清零后调用)
/// </summary>
public static void ConfirmNoWeightCalibration(DarraEtherCAT master, int moduleIndex)
{
ref var output = ref master.Slaves[moduleIndex].OutputsMapping<WeighingModule_Output>();
output.Calibration1 = 16; // 16=确认无砝码标定
}
}