instrument-integration
Skill1 starsChanged 3 months agoMITView on GitHub
Connect to scientific instruments over GPIB, USB, and TCP/IP with PyVISA and PyMeasure, capture data with nidaqmx, run measurement loops, and capture provenance metadata with python logging and structlog. Use when controlling a bench instrument, querying a SCPI identity, or building a measurement loop.
- Installs packages
3 other projects use a version of this.
Adopted by
Most recently taken up by
- PostHog/ai-plugintheir own version, first seen Sep 25, 2026
- PostHog/skillstheir own version, first seen Sep 13, 2026
- Pratikrishi97/sciagent-skillsword for word, first seen Aug 29, 2026
Other versions3 projects use a version of this.
Word for word · 1
- Pratikrishi97/sciagent-skills★ 1100% same
Edited · 0
None found.
Wrote their own version · 2
- PostHog/ai-plugin★ 100same name
- PostHog/skills★ 78same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository41 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- admet-predictionSkill
- astrophysicsSkill
- biostatisticsSkill
- cheminformaticsSkill
- citation-managementSkill
- climate-scienceSkill
- clinical-nlpSkill
- clinical-researchSkill
- computational-chemistrySkill
- computational-physicsSkill
- data-visualizationSkill
- deep-learningSkill
- drug-discoverySkill
- epidemiologySkill
- evolutionary-biologySkill
- experimental-designSkill
- genomicsSkill
- geospatial-analysisSkill
- grant-writingSkill
- hpc-computingSkill
- lab-automationSkill
- literature-reviewSkill
- materials-scienceSkill
- medical-imagingSkill
- ml-for-scienceSkill
- notebook-best-practicesSkill
- protein-analysisSkill
- proteomicsSkill
- quantum-computingSkill
- reaction-modelingSkill
- remote-sensingSkill
- reproducible-environmentsSkill
- reproducible-researchSkill
- retrosynthesisSkill
- scientific-computingSkill
- scientific-data-managementSkill
- scientific-presentationsSkill
- scientific-writingSkill
- transcriptomicsSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 160
Use pyvisa-py (@py) backend so the stack runs without the proprietary NI-VISA runtime.
- Very specific: line 163
Always send *RST after opening an instrument so the start state is reproducible.
- Very specific: line 166
Prefer SCPI query() over write()+read() for round-trip commands.
- Very specific: line 175
Use pyserial for any vendor that ships RS-232 (still common on lock-ins, gas controllers, and older spectrometers).
- Very specific: line 177
Run any heavy compute (FFT, fitting) on a separate thread/process so the measurement loop never blocks on inst.query.
- Very specific: line 277
Instrument safety: always teardown with *RST and set voltage/current to safe defaults in a finally block.
- Distinctive: line 282
Concurrency: never call the same VISA resource from multiple threads without a lock.
- Distinctive: line 284
Privacy: avoid logging patient-identifiable sample labels in raw instrument logs.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Instrument Integration
Overview
Connecting to bench instruments (oscilloscopes, sourcemeters, multimeters, spectrometers, lock-ins) and data acquisition cards turns a laptop into a lab controller. The canonical Python stack is PyVISA (VISA resource manager
- SCPI over GPIB/USB/TCPIP), PyMeasure (measurement-loop orchestration), and
nidaqmx for National Instruments DAQ cards. Every measurement should run
inside a structured-log envelope (python
logging+structlog) that captures instrument IDs, serial numbers, timestamps, and a measurement hash. This skill covers SCPI queries, async-friendly loops, metadata capture, and clean teardown so that a crash mid-run leaves the instrument in a known state.
When to use this skill
- You are controlling an instrument over GPIB, USB, or TCP/IP from Python.
- You need to query an instrument's
*IDN?SCPI identity. - You are building a measurement loop (sweep + collect + plot).
- You need NI DAQmx for analog/digital I/O.
- You want logs that reconstruct who measured what with which hardware.
Prerequisites
- Python 3.10+
- Core:
pyvisa,pyvisa-py(pure-python backend; no NI-VISA needed),pymeasure,nidaqmx,pyserial - Logging:
structlog - Optional:
h5py(for live HDF5 writes),pyqtgraph(for live plots) - System: for VISA hardware access,
pyvisa-pyis recommended; if using NI-VISA, install the NI-VISA runtime - pip install:
pip install pyvisa pyvisa-py pymeasure nidaqmx pyserial structlog pip install h5py pyqtgraph
Core workflows
1. List resources and query identity
import pyvisa
rm = pyvisa.ResourceManager("@py") # use pyvisa-py backend
print(rm.list_resources())
# ('USB0::0x0957::0x0411::MY123456::0::INSTR', 'GPIB0::5::INSTR', ...)
with rm.open_resource("USB0::0x0957::0x0411::MY123456::0::INSTR") as inst:
inst.timeout = 5000
inst.read_termination = "\n"
print(inst.query("*IDN?"))
# -> 'Keysight,Model XYZ,MY123456,A.01.02'
inst.write("*RST") # reset to known state2. SCPI sweep and capture
import pyvisa, structlog
import numpy as np
log = structlog.get_logger().bind(instrument="kepco")
rm = pyvisa.ResourceManager("@py")
def sweep_iv(start=0.0, stop=1.0, n=11):
with rm.open_resource("USB0::0x0957::0x0411::MY123456::0::INSTR") as inst:
inst.read_termination = "\n"
results = []
for v in np.linspace(start, stop, n):
inst.write(f"SOUR:VOLT {v}")
measured = float(inst.query("MEAS:VOLT?"))
current = float(inst.query("MEAS:CURR?"))
log.info("point", set_v=float(v),
meas_v=measured, meas_i=current)
results.append((v, measured, current))
return np.array(results, dtype="f4")3. PyMeasure measurement loop
from pymeasure.instruments.keithley import Keithley2400
from pymeasure.experiment import Procedure, Worker
from pymeasure.experiment.results import Results
from pymeasure.display import Plotter
class IVProcedure(Procedure):
start = 0.0; stop = 1.0; npts = 11
def execute(self):
sm = Keithley2400("GPIB::24")
sm.reset()
for v in np.linspace(self.start, self.stop, self.npts):
self.emit("progress", 100 * (v - self.start) / (self.stop - self.start))
sm.apply_voltage(v)
self.emit("v", v); self.emit("i", sm.current)
results = Results(IVProcedure(), "iv.csv")
worker = Worker(results)
worker.run()4. NI DAQmx analog input
import nidaqmx
from nidaqmx.constants import AcquisitionType
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
task.timing.cfg_samp_clk_timing(rate=1000,
sample_mode=AcquisitionType.FINITE,
samps_per_chan=100)
data = task.read(number_of_samples_per_channel=100)
print(f"mean={sum(data)/len(data):.4f} V")5. Structured logging + provenance
import structlog, hashlib, json, datetime as dt
from pathlib import Path
log = structlog.get_logger().bind(
run_id="run-2024-06-01",
operator="jdoe",
script_version="0.3.0",
)
log.info("start", timestamp=dt.datetime.utcnow().isoformat())
def write_hdf5_with_metadata(path, array, attrs):
import h5py
with h5py.File(path, "w") as f:
d = f.create_dataset("signal", data=array, compression="gzip")
d.attrs["instrument_id"] = "KEPCO-BITS-123456"
d.attrs["firmware"] = "A.01.02"
d.attrs["operator"] = "jdoe"
d.attrs["started_at"] = dt.datetime.utcnow().isoformat()
for k, v in attrs.items():
d.attrs[k] = v
f.attrs["provenance_sha256"] = hashlib.sha256(
json.dumps(attrs, sort_keys=True).encode()
).hexdigest()Best practices
- Use
pyvisa-py(@py) backend so the stack runs without the proprietary NI-VISA runtime; switch to@nionly if you need hardware-specific features. - Always send
*RSTafter opening an instrument so the start state is reproducible. - Wrap instrument access in
withblocks; the connection closes on exit. - Prefer SCPI
query()overwrite()+read()for round-trip commands. - Set
read_terminationto the instrument's documented terminator (often\n); unconfigured reads hang ontimeout. - Log every setpoint/measurement as structured JSON to a file
(
measurement.log), not just stdout. - Capture
*IDN?and firmware version on connect and stash them as HDF5 attrs; reviewers will ask. - For NI-DAQ cards, set
AcquisitionType.FINITEand a known sample rate; continuous acquisition needs an explicit buffer-polling thread. - Use
pyserialfor any vendor that ships RS-232 (still common on lock-ins, gas controllers, and older spectrometers). - Run any heavy compute (FFT, fitting) on a separate thread/process so the
measurement loop never blocks on
inst.query.
Common pitfalls
- Calling
inst.read()afterinst.write("MEAS:VOLT?")instead ofquery(), leaving termination bytes in the buffer for the next call. - Forgetting
read_terminationcauses indefinite hangs onquery. - Opening multiple
ResourceManagerobjects in parallel is safe with pyvisa-py, but with NI-VISA each open has a license cost. - NI-DAQmx continuous mode without a polling loop drops samples silently;
set
samps_per_chanand read in chunks. - Hardcoded GPIB addresses that differ per physical lab; read from a YAML config instead.
- Live plots in the main thread block the SCPI loop; use a separate matplotlib animation or pyqtgraph and a queue.
- Writing raw bytes to CSV loses precision; prefer HDF5 with
gzip. - Forgetting
*RSTon the same instrument that another script left in some weird mode yields impossible readings. - ASRL/serial ports that don't close leak file descriptors; wrap them
in
withblocks.
Worked example
A complete I-V sweep with metadata: open a Keithley 2400 over GPIB, sweep 0-1 V, log every point, write an HDF5 file with provenance, and restore the instrument to a safe state.
import pyvisa, structlog, numpy as np
import h5py, hashlib, json, datetime as dt
log = structlog.get_logger().bind(run_id="iv-2024-06-01", operator="jdoe")
def run_iv(gpib_addr=24, npts=11, out_path="iv_run.h5"):
rm = pyvisa.ResourceManager("@py")
addr = f"GPIB0::{gpib_addr}::INSTR"
with rm.open_resource(addr) as sm:
sm.read_termination = "\n"; sm.timeout = 5000
idn = sm.query("*IDN?")
log.info("connect", resource=addr, idn=idn)
sm.write("*RST")
sm.write(":SENS:FUNC 'CURR'")
rows = []
try:
for v in np.linspace(0, 1.0, npts):
sm.write(f":SOUR:VOLT {v}")
measured_v = float(sm.query(":MEAS:VOLT?"))
measured_i = float(sm.query(":MEAS:CURR?"))
log.info("point", set_v=float(v),
meas_v=measured_v, meas_i=measured_i)
rows.append((v, measured_v, measured_i))
arr = np.array(rows, dtype="f4")
finally:
sm.write("*RST") # safe-state teardown
attrs = {"instrument_id": idn, "operator": "jdoe",
"started_at": dt.datetime.utcnow().isoformat(),
"npts": npts}
with h5py.File(out_path, "w") as f:
d = f.create_dataset("iv", data=arr, compression="gzip")
for k, v in attrs.items():
d.attrs[k] = v
f.attrs["provenance_sha256"] = hashlib.sha256(
json.dumps(attrs, sort_keys=True).encode()
).hexdigest()
log.info("write_complete", file=out_path, rows=len(arr))
if __name__ == "__main__":
run_iv()Tools & libraries
| Tool | Purpose | Install |
| pyvisa | VISA resource manager | pip install pyvisa |
| pyvisa-py | Pure-Python VISA backend | pip install pyvisa-py |
| pymeasure | Measurement loop framework | pip install pymeasure |
| nidaqmx | NI DAQmx API | pip install nidaqmx |
| pyserial | RS-232 instruments | pip install pyserial |
| structlog | Structured logging | pip install structlog |
| h5py | Provenance-rich data files | pip install h5py |
| pyqtgraph | Real-time plotting | pip install pyqtgraph |
| libtiepie | TiePie scopes/AWGs | pip install libtiepie |
| python-usbtmc | Pure-Python USBTMC | pip install usbtmc |
| click | CLI for measurement scripts | pip install click |
References
- PyVISA tutorial: https://pyvisa.readthedocs.io/
- PyVISA-py backend: https://pyvisa-py.readthedocs.io/
- PyMeasure docs: https://pymeasure.readthedocs.io/
- NI-DAQmx Python: https://nidaqmx-python.readthedocs.io/
- SCPI spec (IVI Foundation): https://www.ivifoundation.org/
- structlog: https://www.structlog.org/
- h5py provenance pattern: https://docs.h5py.org/
- libtiepie docs: https://www.tiepie.com/en/libtiepie-sdk-python
Ethics & safety
- Instrument safety: always teardown with
*RSTand set voltage/current to safe defaults in afinallyblock; unhandled exceptions can leave sources driving outputs. - Provenance: log the
*IDN?and firmware of every instrument in every run; reviewers must be able to verify which hardware produced which data. - Concurrency: never call the same VISA resource from multiple threads without a lock; the underlying socket is not thread-safe.
- Privacy: avoid logging patient-identifiable sample labels in raw instrument logs.
- Calibration: record the instrument's last calibration date in the metadata; refuse to publish results from out-of-calibration instruments.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

