Open-source instrument control software compared: drivers, sequencers, evidence

By Alex Hernandez · · 12 min read

View Markdown
A bench digital multimeter in front elevation, blank display, four input jacks and a LAN cable, with three empty callout circles.
FIG. 1 — BENCH DMM, FRONT PANEL

Open-source instrument control software splits into layers. PyVISA and PyVISA-py carry commands to instruments; PyMeasure, QCoDeS, Instro, tm_devices and sigrok supply drivers; OpenHTF and OpenTAP sequence tests and record results; galois-edge serves instruments to scripts and agents over the network. Choose one per layer, by license and language.

Each project below is described from its own documentation, and each license was read from its repository in October 2026.

Open-source instrument control software at a glance

ProjectLicenseLanguageInstrument coverage modelSequencingData and evidenceBest for
PyVISA + PyVISA-pyMIT (both)PythonTransport: you write the SCPI stringsYour Python codeYour loggingThe base layer under the Python driver libraries
PyMeasureMITPythonDriver classes in the package; properties map to commands with validatorsProcedures run by a worker thread; GUI experiment queueCSV results file with parameters in the headerLab measurements with live plots
QCoDeSMITPython 3.11+Drivers built from Parameters; core drivers plus a community repoMeasurement context manager and sweep helpersSQLite dataset; export to xarray, pandas, netCDFNotebook-driven physics experiments
InstroApache-2.0PythonOne class per instrument type, one driver per modelYour Python; optional background acquisitionPublishers to JSONL, CSV or Avro files, or NominalOne API across vendors
tm_devicesApache-2.0PythonPer-model Tektronix and Keithley driversYour PythonYour scriptsTektronix and Keithley benches
sigrokGPL-3.0-or-laterC libraries; Python decodersPer-device drivers in libsigrokCaptures from sigrok-cli or PulseViewCaptures and decoded protocol outputLogic analyzers, bus decoding, meters and loggers
OpenHTFApache-2.0PythonPlugs you writePhases with measurements and limitsTest record; JSON output callbackPython functional and production tests
OpenTAPMPL-2.0C# on .NET; Python pluginInstrument and DUT pluginsXML test plansResult listener plugins.NET teams that want a plugin sequencer
galois-edgeApache-2.0Go and Python daemon; PyVISA, gRPC and MCP clientsYAML profiles matched on *IDN?, raw SCPI, vendor SDK proxyDaemon-resident sweeps; versioned sequences in the Galois platformDaemon audit log; per-step record in the Galois platformShared benches, remote access, agents

Which layer does each tool cover?

Instrument control is four jobs:

  • Transport moves bytes over GPIB, USB, LAN or serial: PyVISA on a vendor VISA library or PyVISA-py.
  • Drivers turn command strings into typed calls with checked arguments. PyMeasure, QCoDeS, Instro and tm_devices each define a driver differently; sigrok's drivers serve capture hardware such as logic analyzers.
  • Sequencing runs steps in order with setup, teardown and pass/fail limits: OpenHTF, OpenTAP, or pytest.
  • Evidence is what a run leaves behind: a CSV, a database of runs, a JSON test record, or a per-step record naming the command, the response and the limit.

galois-edge sits beside these as a service: a daemon on the bench PC that serves its instruments to scripts, other languages and AI agents over the network.

PyVISA and PyVISA-py: the transport layer

PyVISA describes itself as "Python VISA bindings for GPIB, RS232, TCPIP and USB instruments" (PyPI) and is MIT-licensed (pyvisa/pyvisa). It talks to an installed IVI VISA library such as NI-VISA or Keysight VISA, and falls back to PyVISA-py when none is present. PyVISA-py, also MIT (pyvisa/pyvisa-py), is a "Pure Python implementation of a VISA library" (PyPI). It handles LAN instruments out of the box and needs one optional package per bus for USB, serial and GPIB. PyVISA on Linux walks through each one.

PyVISA knows nothing about any particular instrument, by design. You get write(), query(), timeouts, termination and binary block parsing; every command string and range check is yours. PyMeasure, QCoDeS, Instro and tm_devices all reach VISA instruments through it. The SCPI automation guide builds a production script on PyVISA alone, and the Galois and PyVISA comparison covers what a platform adds.

PyMeasure vs QCoDeS: drivers for the research lab

PyMeasure contains "a repository of instrument classes and a system for running experiment procedures, which provides graphical interfaces for graphing live data and managing queues of experiments" (pymeasure/pymeasure, MIT). It is tested in CI on Linux, macOS and Windows.

A PyMeasure driver is a class whose properties map to commands. Three property factories cover the cases: Instrument.control for read and write, Instrument.measurement for read-only, Instrument.setting for write-only. Validators such as strict_range reject bad values before anything reaches the instrument.

pymeasure_supply.py
from pymeasure.instruments import Instrument
from pymeasure.instruments.validators import strict_range
 
 
class BenchSupply(Instrument):
    """A hand-written PyMeasure driver: one property per command."""
 
    voltage_setpoint = Instrument.control(
        "VOLT?", "VOLT %g",
        """Control the output voltage setpoint in volts (float, 0 to 30).""",
        validator=strict_range,
        values=[0, 30],
    )
    output_voltage = Instrument.measurement(
        "MEAS:VOLT?",
        """Measure the output voltage in volts (float).""",
    )
 
    def __init__(self, adapter, name="Bench supply", **kwargs):
        super().__init__(adapter, name, **kwargs)
 
 
psu = BenchSupply("TCPIP0::192.168.1.60::inst0::INSTR")
psu.voltage_setpoint = 5.0
print(psu.output_voltage)

The other half of PyMeasure is the Procedure: you declare typed Parameters and DATA_COLUMNS, write startup(), execute() and shutdown(), and call emit('results', ...) for each point. A Worker runs it in its own thread, and the Results class writes a CSV whose header records the parameter values.

QCoDeS is "a Python-based data acquisition framework developed by the Copenhagen / Delft / Sydney / Microsoft quantum computing consortium," and is "primarily intended for use from Jupyter notebooks" (microsoft/Qcodes, MIT, Python 3.11+).

A QCoDeS driver subclasses VisaInstrument for text protocols and adds Parameters, each with a unit, get and set commands, a parser and a validator. Core drivers live under qcodes/instrument_drivers/; community drivers live in the separate qcodes_contrib_drivers repository.

qcodes_supply.py
from qcodes import validators as vals
from qcodes.instrument import VisaInstrument
 
 
class BenchSupply(VisaInstrument):
    def __init__(self, name: str, address: str, **kwargs):
        super().__init__(name, address, terminator="\n", **kwargs)
        self.voltage = self.add_parameter(
            "voltage",
            label="Output voltage setpoint",
            unit="V",
            get_cmd="VOLT?",
            set_cmd="VOLT {}",
            get_parser=float,
            vals=vals.Numbers(0, 30),
        )
 
 
psu = BenchSupply("psu", "TCPIP0::192.168.1.60::inst0::INSTR")
psu.voltage(5.0)
print(psu.voltage())

Data is where the two diverge most. QCoDeS stores runs in SQLite database files, grouped into experiments, written through the Measurement context manager or its sweep helpers, and exportable to xarray, pandas and netCDF. PyMeasure writes one CSV per run. Pick PyMeasure for a measurement with a GUI and a file per run; pick QCoDeS for notebook sweeps over many parameters with a queryable history.

Instro: Nominal's vendor-agnostic driver library

Instro is Nominal's "open-source, vendor-agnostic Python library for interfacing with test equipment," Apache-2.0, copyright Nominal, Inc. (nominal-io/instro).

Instro's coverage model is one class per instrument type (InstroPSU, InstroDMM, InstroScope, InstroDAQ and others), each backed by a driver per model. Swap the driver and the test code stays the same. Supported hardware includes power supplies from B&K Precision, EA Elektro-Automatik, Keysight, Rigol, Siglent and TDK Lambda; Keysight, Agilent and Keithley meters; NI-DAQmx, LabJack and MCC data acquisition; and Modbus and EtherNet/IP devices. instro discover scans VISA resources and serial ports and names the driver class for each instrument.

instro_supply.py
from instro.lib.publishers import FilePublisher
from instro.psu import InstroPSU
from instro.psu.drivers import RigolDP800
# from instro.psu.drivers import SiglentSPD3303  # swap the driver, keep the test
 
pub = FilePublisher(directory="/tmp/instro/", format="jsonl")
 
with InstroPSU(
    name="bench_psu",
    driver=RigolDP800("TCPIP0::192.168.1.60::INSTR"),
    num_channels=3,  # DP832
    publishers=[pub],
) as psu:
    psu.set_voltage(5.0, channel=1)
    psu.set_current_limit(1.0, channel=1)
    psu.output_enable(True, channel=1)
    voltage = psu.get_voltage(channel=1)
    print(f"V: {voltage.latest:.3f} V")

Every command and measurement flows to Publishers: JSONL, CSV or Avro files, or Nominal's platform. Instruments can be read on demand or in a background loop. Sequencing comes from whatever runs Instro, whether pytest, OpenHTF or a script.

tm_devices: Tektronix and Keithley drivers from Tektronix

tm_devices is Tektronix's own package, Apache-2.0, copyright Tektronix (tektronix/tm_devices). It describes itself as "a device management package which allows for better control and usage of Test & Measurement devices in python scripts."

A DeviceManager opens and tracks connections, and each supported model gets a driver with "a complete Python API" (documentation). Coverage spans Tektronix and Keithley oscilloscopes, AWGs, AFGs, power supplies, SMUs, multimeters and DAQs, over VISA, sockets, USBTMC, GPIB, serial, or REST API where a device offers one.

Because Tektronix maintains the drivers, you call driver methods instead of writing most command strings for those two brands; the rest of a mixed bench needs another library.

sigrok: logic analyzers, meters and protocol decoders

sigrok "aims at creating a portable, cross-platform, Free/Libre/Open-Source signal analysis software suite" and is licensed under "the GNU GPL, version 3 or later" (sigrok wiki; libsigrok COPYING). It runs on Linux, macOS, Windows, the BSDs and Android.

Supported devices include logic analyzers, mixed-signal devices, oscilloscopes, multimeters, LCR meters, dataloggers, electronic loads, power supplies and more. libsigrok holds the per-device drivers; libsigrokdecode is a C library whose protocol decoders are written in Python; sigrok-cli and the PulseView GUI drive captures.

sigrok's job is capture and decode: watch an SPI, I2C or UART line, decode it, and save the result. It pairs with a sequencer when a test has to check what crossed a bus.

OpenHTF and OpenTAP: open-source test sequencers

Above the driver layer sit the sequencers. OpenHTF (Apache-2.0, Python) builds a test from phases whose measurements carry their own limits, with plugs wrapping the DUT and instruments (google/openhtf). OpenTAP (MPL-2.0, C# with a Python plugin) runs XML test plans of steps against instrument and DUT resources (opentap/opentap). Keysight's PathWave Test Automation is built on it, and PathWave Test Automation alternatives explains what Keysight adds to the engine. Neither OpenHTF nor OpenTAP bundles bench-instrument drivers, so a DMM or supply plug wraps one of the libraries above. OpenHTF vs OpenTAP vs pytest vs TestStand compares them with code.

galois-edge: an instrument daemon for scripts and agents

galois-edge is the open-source part of Galois: Apache-2.0, a Go supervisor plus a frozen Python engine that needs no Python runtime on the host, built for Linux (x86_64 and arm64, including Raspberry Pi) and Windows (Galois-Labs/edge). It walks GPIB, USB, LAN, serial, Modbus and CAN, identifies SCPI instruments with *IDN?, and matches each reply against YAML instrument profiles. Instruments without a profile still accept raw SCPI, and a vendor SDK proxy wraps Python libraries for non-SCPI hardware.

keysight_34461a.yaml
instrument:
  manufacturer: "Keysight"
  model: "34461A"
  class: dmm
 
identity:
  query: "*IDN?"
  patterns:
    - "(?:Keysight|Agilent).*34[4-7][0-9][0-9]A"
 
commands:
  measure_voltage_dc:
    scpi: "MEAS:VOLT:DC?"
    type: query
    returns:
      type: float
      unit: V

The coverage model is data rather than classes: a profile declares commands, parameters, units and ranges, and typed methods and MCP tools are generated from it. Galois ships 573 instrument profiles across 135 manufacturers in its instrument library, and the PDF-to-driver pipeline in the Galois platform generates new profiles from instrument manuals. Declarative instrument drivers covers the trade-off against hand-written classes like the PyMeasure and QCoDeS examples above.

Three client surfaces reach the same instruments:

  • PyVISA. Existing scripts change one line, pyvisa.ResourceManager("@galois"), and reach instruments on any bench through Galois Cloud (PyVISA backend docs).
  • gRPC. The edge.proto contract generates clients in any language, and the typed galois Python SDK decodes waveforms into NumPy.
  • MCP. Each connected instrument appears as typed Model Context Protocol tools, with sweeps that keep running on the daemon if an agent session drops; measurement streams end on disconnect (agent docs).

Sequencing and evidence live in the Galois platform rather than the daemon: versioned sequences, an approval gate that keeps a sequence Évariste, the agent in the Galois platform, drafts from running until an engineer approves it, and a record for every step with the SCPI sent, the raw response, the measured value, its limits and the instrument, plus the operator and DUT serial on the run (product).

Évariste does the same work as the supply examples above, on the same Rigol DP832, without a driver class or a script. If the DP832 has no profile in the library, upload the DP800 programming guide and Évariste generates one. Check its commands, units and ranges against the manual, as you would review the PyMeasure or QCoDeS class, before Évariste deploys it to the bench's galois-edge and binds it to the supply.

Then state the objective, "Set channel 1 of the DP832 to 5.0 V with a 1.0 A current limit, turn the output on and measure the output voltage," with a pass band built from the DP832's datasheet accuracy, for example "pass from 4.965 to 5.035 V," which allows channel 1's programming accuracy of ±(0.05% + 20 mV) plus its readback accuracy of ±(0.05% + 10 mV) at 5 V. Évariste drafts a sequence that does not run until you approve it; ask for changes in conversation or edit it in the sequence builder, and each change is saved as a new version. Once you approve it, the sequence runs on the supply through galois-edge, and if you send a command flagged as dangerous straight from the conversation, Évariste asks you to confirm it first. After the run, Évariste flags steps that failed or passed close to a limit, compares the run with earlier ones and generates a test report. The driver class, the script, and the logging and report code a production test would add are no longer yours to maintain; the objective, the limits, reviewing and approving the draft, wiring the supply and bench safety stay with you.

How do the open-source licenses differ?

Seven of the nine use permissive licenses. PyVISA, PyVISA-py, PyMeasure and QCoDeS are MIT; Instro, tm_devices, OpenHTF and galois-edge are Apache-2.0, which adds an express patent license from contributors. Both let you ship the code inside proprietary test software if you keep the license and copyright notices; Apache-2.0 also asks you to mark files you change.

OpenTAP's MPL-2.0 is copyleft at the file level. In Mozilla's words, it encourages contributors "to share modifications they make to your code, while still allowing them to combine your code with code under other licenses (open or proprietary)" (MPL 2.0 FAQ). Changes you distribute to OpenTAP's own files stay MPL; plugins in your own files need not.

sigrok's GPL-3.0-or-later asks the most, mainly of distributors. The FSF's FAQ says an organization "can make a modified version and use it internally without ever releasing it outside the organization" (GPL FAQ). It also says "pipes, sockets and command-line arguments are communication mechanisms normally used between two separate programs" (GPL FAQ), so driving sigrok-cli from a test script differs from linking libsigrok into a product you ship. Check that case with counsel.

Which open-source stack fits your bench?

Pick one project per layer, starting from the job:

  • One engineer, a few SCPI instruments. PyVISA, a session class, and pytest. Add a driver library when the same command strings appear in several scripts.
  • A research lab running sweeps. QCoDeS for notebooks and a database of runs; PyMeasure for a GUI, an experiment queue and a CSV per run. Lab automation for university research labs covers shared drivers, safe temperature and field sweeps, and reproducible data.
  • A fixture that has to survive vendor swaps. Instro drivers under OpenHTF or pytest, so replacing a supply means changing one constructor.
  • A Tektronix and Keithley bench. tm_devices.
  • Tests that check digital buses. sigrok next to whichever sequencer you run.
  • A .NET team that wants a TestStand-shaped sequencer. OpenTAP.
  • Several benches, remote users, or agents. galois-edge on each bench PC, with the Galois platform when you want versioned sequences and a per-step record across them.

A common Python stack is PyVISA, one driver library, and OpenHTF or pytest on top. Python is also what employers ask for: in our study of 1,021 full-text hardware-test job postings, 54.8% named Python and 7.1% named LabVIEW (hiring study).

When PyVISA alone or LabVIEW is the better choice

Every layer here is another dependency to pin, update and teach. Stay with PyVISA alone when the bench has a handful of instruments, the scripts work, and one person maintains them. A driver library pays off when instruments or people multiply.

Stay with LabVIEW when the switching cost is higher than the return:

  • Your team is fluent in LabVIEW and your VIs are tested and stable. A rewrite buys reviewable text, not new measurements.
  • Your hardware is NI's. On DAQmx, PXI and CompactRIO systems, LabVIEW and the drivers come from one vendor, and so does support.
  • You want an agent without a migration. NI's agent, Nigel, runs inside LabVIEW with a valid license and an active software service agreement, and LabVIEW 2026 Q3 creates VIs from a prompt (NI, Nigel).
  • The cost is already budgeted. LabVIEW Professional is $2,805 a year at NI's US list price, read October 5, 2026, and migrating a large code base has its own cost.

Source: LabVIEW editions, ni.com

If those do not hold, the open-source layers above cover most of the same ground in reviewable Python. The LabVIEW to Python migration plan phases the move, and the Galois and LabVIEW comparison goes line by line. To put galois-edge on a bench, start with the quickstart.

Frequently asked questions

What is the best open-source instrument control software?
It depends on the layer you need. PyVISA (MIT) is the transport the Python driver libraries sit on. For drivers, PyMeasure and QCoDeS (both MIT) suit research labs, Instro (Apache-2.0) gives one typed API across vendors, and tm_devices (Apache-2.0) covers Tektronix and Keithley. For test sequencing with limits, OpenHTF (Apache-2.0, Python) and OpenTAP (MPL-2.0, .NET) are open-source sequencers.
Is PyVISA free for commercial use?
Yes. PyVISA and its pure-Python backend PyVISA-py are both released under the MIT License, which permits commercial use as long as the copyright and license notice are kept. PyVISA can use a vendor VISA library such as NI-VISA or Keysight VISA, which carry their own license terms, or PyVISA-py, which needs no vendor install.
What is the difference between PyMeasure and QCoDeS?
Both are MIT-licensed Python packages with instrument drivers built on PyVISA. PyMeasure pairs driver classes with Procedures that run in a worker thread, plot live data in a GUI and write a CSV file per run. QCoDeS, from the Copenhagen, Delft, Sydney and Microsoft quantum computing consortium, is notebook-first: drivers expose Parameters, and the Measurement context manager stores runs in an SQLite database you can export to xarray, pandas or netCDF.
Can I use GPL-licensed sigrok in commercial test software?
sigrok is licensed under the GNU GPL, version 3 or later. The FSF's GPL FAQ says an organization can modify GPL software and use it internally without releasing it, and that programs communicating through pipes, sockets and command-line arguments are normally separate programs. Distributing a program linked against libsigrok is different, so check that case with counsel.
Is there an open-source alternative to LabVIEW for instrument control?
A Python stack covers much of the same ground in layers: PyVISA for transport, a driver library such as PyMeasure, QCoDeS, Instro or tm_devices, and a sequencer such as OpenHTF or pytest for tests with limits. The galois-edge daemon (Apache-2.0) adds network access to instruments for scripts and AI agents.

Related

Bring Galois to your bench.

The daemon is Apache-2.0, free forever. Enterprise runs in your cloud or on-prem.