One InstroDAQ instance drives one NIDAQDriver, and that driver owns one NI DAQmx task per subsystem (analog input, digital input, digital output). The analog input task carries a single hardware sample rate. To run more than one acquisition at a time (more than one task, or more than one hardware sample rate), create multiple InstroDAQ instances: one per task, each with its own NIDAQDriver.
This is the supported pattern. instro has no task framework or task-level API; multiple tasks means multiple InstroDAQ instances.
When to use this pattern
- Multiple hardware sample rates. A single analog input task samples every channel at one rate. To sample a vibration sensor at 10 kHz and a temperature sensor at 10 Hz, give each its own instance.
- Independent lifecycles. Each instance starts, stops, and closes on its own. Stop a short acquisition while a long one keeps running.
- Separate publishing. Each instance has its own
name (the channel prefix) and its own publishers, so each acquisition can target a different dataset.
Constructing the instances
Give each instance its own NIDAQDriver and a unique name. Both drivers can target the same device:
from instro.daq import InstroDAQ
from instro.daq.drivers.ni import NIDAQDriver
daq_fast = InstroDAQ(name="daqFast", driver=NIDAQDriver(device_id="cDAQ1"))
daq_slow = InstroDAQ(name="daqSlow", driver=NIDAQDriver(device_id="cDAQ1"))
Do not share one NIDAQDriver between two InstroDAQ instances. The driver is the single source of truth for its channels and timing, and two HALs mutating one task set will conflict.
Allocating channels across instances
A physical channel belongs to exactly one instance: DAQmx reserves a physical channel for the task that configures it, so never configure the same physical channel on two instances. How to partition the remaining channels across instances is up to you and your hardware; a single instance’s task can span channels from multiple modules on a chassis.
from instro.daq.types import Direction
# Channels are allocated per instance, with no overlap.
daq_fast.configure_analog_channel(
direction=Direction.INPUT, physical_channel="cDAQ1Mod1/ai0", alias="vibration", range_min=-5, range_max=5
)
daq_slow.configure_analog_channel(
direction=Direction.INPUT, physical_channel="cDAQ1Mod2/ai0", alias="temperature", range_min=0, range_max=5
)
# Each instance carries its own hardware sample rate.
daq_fast.configure_ai_sample_rate(sample_rate=10000)
daq_slow.configure_ai_sample_rate(sample_rate=10)
Lifecycle per instance
Each instance follows the normal InstroDAQ lifecycle on its own: open(), configure, start(), read, stop(), close(). start() launches that instance’s own background daemon, so the two acquisitions fetch and publish concurrently without coordinating.
daq_fast.open()
daq_slow.open()
try:
# ... configure channels and sample rates per instance ...
daq_fast.start()
daq_slow.start()
fast_data = daq_fast.get_channel("daqFast.vibration", 100, True)
slow_data = daq_slow.get_channel("daqSlow.temperature", 1, False)
# Stopping one acquisition does not affect the other.
daq_fast.stop()
daq_slow.stop()
finally:
daq_fast.close()
daq_slow.close()
Check your device’s capabilitiesHow many DAQmx tasks a device can run concurrently, and at which combinations of subsystems and sample rates, varies per device. Consult your device’s documentation. When the hardware cannot run an additional task, DAQmx raises a reserved-resource error when that task starts. Per-device aggregate sample rate limits also still apply: splitting channels across instances does not raise a device’s total throughput.
See the full runnable example: NI multi-rate acquisition with two InstroDAQ instances.