使用 Comedi 进行数据采集

作者:Caleb Tennis

大多数科学家和工程师都喜欢数据。您提供的数据越多,他们就越高兴。在实验室环境中,数据意味着一切。为了发现趋势、分析奇怪现象并得出最终结论,实验室人员需要确保他们已获取完整的数据集。

因此,数据采集的概念涵盖了广泛的想法。然而,大多数科学家和工程师都认同,数据采集是对某些自然过程进行测量的结果。这可能像测量温度一样简单,也可能像测量熔融钢中的杂质一样复杂。

在计算机世界中,数据采集最常见的做法是测量电压。为此,必须配备某种传感器或测量设备,该设备能够产生计算机可以测量的电压。了解被测参数与传感器电压输出之间的相关性也很重要。理想情况下,相关性是线性的,例如在温度传感器中,测量的 1 摄氏度对应于 0.1 伏电压。

现代主板具有板载传感器,例如 National Semiconductor 的 LM78,用于评估系统的整体健康状况。这些传感器测量诸如冷却风扇速度、处理器核心电压和温度以及硬盘驱动器转速等条件。此信息由芯片采集,可以通过串行总线报告给处理器。开源项目 lm_sensors (secure.netroedge.com/~lm78) 提供了用于监控主板许多方面的软件。

然而,典型的个人计算机没有用于模拟数据采集的通用接口。为了进行一些外部电压测量,需要一个新的接口。为 PCI 或 ISA 总线设计的数据采集 (DAQ) 卡填补了这一空白。许多制造商生产的卡非常适合进行外部测量。

表 1. 常见数据采集通道类型

名称描述
模拟输入测量外部信号,例如电压
模拟输出发送可变信号
数字输入/输出离散的开/关信号;通常 0 代表关,5 伏特代表开
计数器可以计数脉冲数或测量频率
定时器可以测量两个数字脉冲之间经过的时间量
Comedi 项目

大多数 Linux 用户都亲身经历过拥有单一类型的系统(例如打印机)和多种型号、制造商、供应商和驱动程序所带来的复杂性。任何标准化的尝试都会成为一个大型项目。如果该项目获得足够的支持,它就会成为标准。一些供应商,如 National Instruments,发布了其 DAQ 产品的 Linux 驱动程序,而另一些供应商则没有。

Comedi,或控制和测量设备接口,是 Linux 的标准数据采集驱动程序和库套件。Comedi 由 David Schleef 于 1996 年启动,旨在通过通用接口支持多种供应商和型号的卡。事实上,整体 API 设计是模块化和复杂性之间的平衡。与其他 Linux 驱动程序项目一样,部分工作是大量阅读硬件手册的结果,部分是逆向工程的结果,部分是制造商协助为其产品提供 Comedi 支持的结果。

工作原理

Comedi 分为两个部分。Comedi 本身是加载到内核空间的驱动程序包,而 comedilib 提供用户空间对这些驱动程序的访问。正是通过 comedilib,Comedi 的透明性得以彰显。使用 Comedi 的程序可以用 C 或 C++ 编写。Perl 和 Python 绑定也存在于 Comedi 中。

Comedi 将事物分解为通道、子设备和设备。通道是最低级别的测量或控制。相同类型的多个通道被分组到一个公共集合中,称为子设备。然后将多个子设备分组到一个完整的设备中。使用 Comedi 时,首先将 Comedi 驱动程序加载到内存中。然后,/usr/sbin/comedi_config运行以将驱动程序绑定到 Comedi 设备,例如 /dev/comedi0。最后,comedilib 中提供了函数来访问 DAQ 卡上的各种设备。

实验室示例

DAQ 和 Comedi 的一个应用示例是 Analytical Engineering, Inc. (AEI) 气流实验室。在 AEI 实验室中,气流由风扇产生,并被迫通过各种尺寸的孔口。使用定制编写的软件应用程序,技术人员可以监控孔口上的压力积聚。反过来,这种压力积聚可用于计算流过孔口的大致气流量。此计算至关重要,因为它允许技术人员确定各种仪表校准是否正确。

然而,实际的质量流量更难以完全计算。这个数字需要了解两个气压、三个气流温度、湿度、大气压力和海拔高度。

现有的现成组件可以将这些测量值转换为电压;最流行的接口之一是 5B。使用 5B 模块化块,可以将所有这些测量值转换为 DAQ 卡可以读取的电压。

Data Acquisition with Comedi

图 1. 气流测量装置

使用 Comedi,读取这些电压变得像使用 comedi_data_read 函数一样简单。调用此函数并指定某个通道会产生一个结果值,例如 3,421。但是这个数字是什么意思呢?

DAQ 卡以一定的位精度进行测量,12 位是最常见的。它们还指定了可以编程测量的电压范围或多个范围。由于 12 位数字表示为 0 到 4,095,因此很容易看出 3,421 只是满量程 (4,095) 的 3,421/4,095 * 100%。如果电压范围指定为 [0, 5],则 3,421 将代表 4.177 伏特。

利用此信息并了解温度的 5B 模块映射为 [0 伏特 – 5 伏特] → [0°C – 100°C],少量编程数学运算即可得出 83.56°C 的温度。将所有这些测量值耦合在一起,添加一个友好的 GUI 界面,并每秒重复 DAQ 过程。

也可以执行更复杂的数据采集。采集数据时,务必确保采样速度足够快,以免错过样本之间发生的任何重要信息。为了支持这一点,Comedi 提供了一个命令接口,可用于设置同步采样。根据 DAQ 卡的复杂程度,定时可以由软件中断或板载中断处理。

列表 1. 从一个通道采集电压的示例程序

#include <stdio.h>
#include <comedilib.h>

const char *filename = "/dev/comedi0";
int main(int argc, char *argv[])
{
  lsampl_t data;
  int ret;
  comedi_t *device;

  /* Which device on the card do we want to use? */
  int subdevice = 0;
  /* Which channel to use */
  int channel   = 0;
  /* Which of the available ranges to use */
  int range     = 0;
  /* Measure with a ground reference */
  int analogref = AREF_GROUND;

  device = comedi_open(filename);
  if(!device){
    /* We couldn't open the device - error out */
    comedi_perror(filename);
    exit(0);
  }

  /* Read in a data value */
  ret=comedi_data_read(device,subdevice,
    channel,range,analogref,&data);

  if(ret<0){
    /* Some error happened */
    comedi_perror(filename);
    exit(0);
  }

  printf("Got a data value: %d\n", data);
  return 0;
}

Comedi 在大多数数据采集应用中都表现出色。事实上,Comedi 的限制通常在于其运行的硬件。价格较低的卡通常具有较慢的扫描速率能力。对于快速数据采集,大多数价格较高的卡都配备了板载 DMA,允许板载处理器处理采集,并允许 Comedi 简单地路由采集到的缓冲数据。

列表 2. 使用命令和触发器演示更高级扫描的代码片段

  /* Goal: Set up Comedi to acquire 2 channels, and
     scan each set twice.  Perform the acquisition
     after receiving a trigger signal on a digital
     line.
  */

  comedi_cmd c, *cmd=&c;
  unsigned int chanlist[2];

  /* CR_PACK is a special Comedi macro used to
     setup a channel, a range, and a ground
     reference
  */

  chanlist[0] = CR_PACK(0,0,0);
  chanlist[1] = CR_PACK(1,0,0);

  /* Which subdevice should be used? */
  /* Subdevice 0 is analog input on most boards */
  cmd->subdev       = 0;
  cmd->chanlist     = chanlist;
  cmd->chanlist_len = n_chan;

  /* Start command when an external digital line
     is triggered.   Use digital channel specified
     in start_arg
  */

  cmd->start_src = TRIG_EXT;
  cmd->start_arg = 3;

  /* begin scan immediately following trigger */
  cmd->scan_begin_src = TRIG_FOLLOW;
  cmd->scan_begin_arg = 0;

  /* begin conversion immediately following scan */
  cmd->convert_src = TRIG_NOW;

  /* end scan after acquiring
     scan_end_arg channels
  */
  cmd->scan_end_src =     TRIG_COUNT;
  cmd->scan_end_arg =     2;

  /* Stop the command after stop_arg scans */
  cmd->stop_src =         TRIG_COUNT;
  cmd->stop_arg =         2;

  /* Start the command */
  comedi_cmd(device, cmd);

然而,快速扫描速率并不转化为快速处理。由于库存 Linux 内核的非确定性性质,几乎不可能实时处理采集和处理——也就是说,为进程维护严格的调度要求。但是,有帮助可用。Linux 实时应用程序接口 (RTAI) 和 RTLinux 是少数几个附加软件包中的两个,这些软件包允许在内核中更好地控制定时。这两个软件包都提供了与 Comedi 的接口。

这些实时接口背后的基本思想很简单。不要将内核作为唯一的单片进程运行,而是将其作为小型高效调度程序的子进程运行。这种设计可以防止内核阻止中断并允许其被抢占。然后,任何需要实时控制系统的应用程序都可以向调度程序注册自身,并根据需要经常抢占内核。

Data Acquisition with Comedi

图 2. 正常 Linux 进程调度与实时 Linux 进程调度

实验室示例

AEI 维护着许多用于柴油发动机的测试室,称为测试单元。在单元中,发动机配备了许多温度和压力测量设备。频率测量设备也用于测量发动机的转速。最后,发动机连接到测功机,测功机通过改变对旋转发动机的阻力来模拟实际驾驶条件。这会产生扭矩,扭矩也会被测量。

Data Acquisition with Comedi

图 3. 正在进行仪器的发动机

发动机数据的实际扫描速率很慢,每秒仅 20 次。如果此数据的测量是唯一需要完成的工作,那么整体设置将很简单。但是,必须使用每组数字的最新采集来调整和控制许多可变参数。必须稍微改变发动机节气门位置和测功机负载量,以将发动机转速保持在特定条件下。必须调整单元中控制冷却水流量的阀门,以将发动机冷却液温度保持在恒定水平。必须检查安全措施以确定是否没有发生灾难性问题。

Data Acquisition with Comedi

图 4. 使用 Comedi 进行发动机测量和控制的概述

所有这些检查和新的控制值都必须在内核可以返回处理其余调度之前完成。如果 Linux 内核自行处理此调度,则一切很可能正常工作。但是,不可能预先确定流程的每个阶段何时执行。但是,借助实时扩展,问题变得微不足道。

实时内核并非没有缺点。当实时调度程序以固定间隔执行某些进程时,Linux 内核基本上处于暂停状态。这意味着实时进程必须快速高效,并且必须尽快将控制权交还给内核。否则会导致系统的非实时部分运行缓慢。如果实时进程中出现问题并且控制权永远不会返回给内核,则也可能发生完整的系统锁定。

实际示例

除了实验室之外,有时在家中使用 Comedi 也很有趣。低端多用途数据采集卡的购买价格在 99 美元到 299 美元之间,具体取决于品牌、复杂性和采集速率。家庭项目的一些示例包括监控房屋各个部分的温度或扫描车库门上的磁传感器以提醒您车库门仍然打开。

个人计算机的一个有趣方面是并行端口线可以单独控制。使用 Comedi,打开和关闭这些数字线路非常简单。当与某种形式的继电器一起使用时,这些数字线路可以打开和关闭任何可以想象到的东西。

虽然并行端口在 0 伏特和 5 伏特之间切换,但它们通常没有能力输出大量电流。也就是说,在不添加某种缓冲电路的情况下将并行端口线直接连接到设备以打开或关闭设备,这是一个坏主意。许多网站都解释了如何创建这些电路。

我使用 Comedi、一台旧的 486 和两个并行端口来创建一个年度节日灯光秀。灯光以正常方式悬挂在房屋上,每组灯光的一对电线都延伸回控制室(在本例中是备用卧室)。这些电源线连接到定制的电路板,该电路板装有机械继电器,当它们接收到来自并行端口的 5 伏特信号时,继电器会将电源发送到灯光。一个简单的 C 程序使用 Comedi 函数调用以数字方式控制并行端口线,即打开和关闭灯光。简单的文本文件告诉程序何时打开和关闭各种灯光。而且,社区也得到了款待。

Data Acquisition with Comedi

图 5. 并行端口灯光秀显示器的接口板

结论

数据采集在实验室中非常有价值。Comedi 提供的通用接口使得在 Linux 中可以轻松使用大量可用的 DAQ 卡。随着 Linux 的普及,拥有像 Comedi 这样的接口变得至关重要。

此外,随着低端 DAQ 卡变得越来越便宜,基于 Linux 的数据采集对业余爱好者和 DIY 爱好者越来越有吸引力。曾经是一套昂贵的软件和硬件,现在已成为多种应用的可行实现方法。

本文资源: /article/7610

Caleb Tennis 自 1996 年以来一直使用 Linux。他曾是 KDevelop 项目的发布协调员,现在专注于维护 Gentoo 的 KDE。除了监督柴油发动机测试设施的工程外,他还在当地大学兼职教授 Linux。

加载 Disqus 评论