PyVISA
PyVISADocs

SCPI Commands

SCPI command reference for PyVISA with error codes, command tree, and Python examples for instrument control.

SCPI (Standard Commands for Programmable Instruments) is the command language behind virtually every modern test instrument. This page covers the commands you'll use most, with PyVISA examples.

IEEE 488.2 Common Commands

Every SCPI instrument supports these:

import pyvisa

rm = pyvisa.ResourceManager()
inst = rm.open_resource('TCPIP::192.168.1.100::INSTR')

idn = inst.query('*IDN?')     # Identification
inst.write('*RST')             # Reset to defaults
inst.write('*CLS')             # Clear status registers
inst.query('*OPC?')            # Wait for operation complete
errors = inst.query('SYST:ERR?')  # Check error queue

Measurement Commands

# DC voltage
voltage = float(inst.query('MEAS:VOLT:DC?'))

# AC voltage with range
inst.write('MEAS:VOLT:AC:RANG 10')
ac_voltage = float(inst.query('MEAS:VOLT:AC?'))

# Current and resistance
current = float(inst.query('MEAS:CURR:DC?'))
resistance = float(inst.query('MEAS:RES?'))

Configuration Commands

# Measurement range
inst.write('VOLT:DC:RANG 10')       # 10V range
inst.write('CURR:DC:RANG 0.1')      # 100 mA range

# Integration time (NPLC)
inst.write('VOLT:DC:NPLC 10')       # 10 power line cycles

# Auto-ranging
inst.write('VOLT:DC:RANG:AUTO ON')

Log measurements automatically

TofuPilot records SCPI measurement results from your PyVISA scripts, tracks pass/fail rates, and generates compliance reports. Free to start.

Error Checking

Always drain the error queue after a sequence of commands. The queue holds up to 20 errors on most instruments.

def check_errors(inst):
    """Read all errors from the instrument queue."""
    errors = []
    while True:
        err = inst.query('SYST:ERR?')
        if err.startswith('0') or err.startswith('+0'):
            break
        errors.append(err.strip())
    return errors

errors = check_errors(inst)
if errors:
    print(f"Errors: {errors}")

Synchronization

Use *OPC? to block until the instrument finishes. Use *WAI to hold the instrument's command queue.

# Block Python until the instrument finishes
inst.write('INIT')
inst.query('*OPC?')  # Returns '1' when done

# Or use service request
inst.write('*ESE 1')     # Enable OPC in standard event register
inst.write('*SRE 32')    # Enable standard event in status byte
inst.write('INIT')
inst.wait_for_srq()       # Block until SRQ fires

Data Transfer

Binary transfers are 5-10x faster than ASCII for large datasets.

# ASCII (human-readable, slower)
data_ascii = inst.query('TRAC:DATA? TRAC1')
values = [float(x) for x in data_ascii.split(',')]

# Binary (faster)
inst.write('FORM:DATA REAL,32')  # 32-bit floats
data = inst.query_binary_values('TRAC:DATA? TRAC1', datatype='f')

Instrument-Specific Commands

Digital Multimeters

# Keysight 34401A/34461A style
inst.write('CONF:VOLT:DC 10,0.0001')  # Range 10 V, resolution 0.1 mV
inst.write('TRIG:SOUR IMM')
measurement = float(inst.query('READ?'))

Oscilloscopes

inst.write('ACQ:MODE RTIME')          # Real-time acquisition
inst.write('ACQ:SRAT 1E9')            # 1 GSa/s
inst.write('CHAN1:SCAL 0.1')          # 100 mV/div
inst.write('TRIG:SOUR CHAN1')
inst.write('TRIG:LEV 0.5')            # 500 mV trigger level
waveform = inst.query_binary_values('CURV?', datatype='h')

Signal Generators

inst.write('SOUR:FUNC SIN')
inst.write('SOUR:FREQ 1000')          # 1 kHz
inst.write('SOUR:VOLT 1')             # 1 Vpp
inst.write('OUTP ON')

SCPI Data Types

TypeExamplesNotes
IntegerSYST:BEEP:FREQ 1000No decimal point
RealSOUR:VOLT:AMPL 2.5Decimal or exponential (1.5E3)
BooleanOUTP ON, OUTP 1, OUTP TRUEAll three forms are equivalent
StringDISP:TEXT "Hello"Quoted for special characters

Timeout Management

Some commands (self-test, calibration, long acquisitions) take much longer than the default 2-second timeout.

from contextlib import contextmanager

@contextmanager
def temporary_timeout(inst, timeout_ms):
    old = inst.timeout
    inst.timeout = timeout_ms
    try:
        yield inst
    finally:
        inst.timeout = old

# 60-second timeout for self-test
with temporary_timeout(inst, 60000):
    result = inst.query('*TST?')

Common SCPI Error Codes

CodeMeaningTypical Cause
-100Command ErrorSyntax error or unknown command
-101Invalid CharacterIllegal character in command string
-102Syntax ErrorMissing parameter or wrong separator
-103Invalid SeparatorWrong use of comma or semicolon
-104Data Type ErrorString sent where number expected
-108Parameter Not AllowedToo many parameters
-109Missing ParameterRequired parameter omitted
-113Undefined HeaderCommand not recognized by this instrument
-200Execution ErrorCommand recognized but cannot execute
-221Settings ConflictParameters conflict with each other
-222Data Out of RangeParameter value outside valid range
-224Illegal Parameter ValueParameter value not in the allowed set

SCPI Command Tree Reference

*CLS                    # Clear status
*ESE <value>           # Standard event status enable
*ESR?                  # Standard event status register
*IDN?                  # Identification query
*OPC                   # Operation complete (set ESR bit)
*OPC?                  # Operation complete query (returns "1")
*RST                   # Reset
*SRE <value>           # Service request enable
*STB?                  # Status byte query
*TST?                  # Self-test query
*WAI                   # Wait to continue

SYSTEM
  :ERRor?              # Error queue query
  :VERSion?            # SCPI version query

MEASure
  :VOLTage
    :DC? [@<list>]     # DC voltage measurement
    :AC? [@<list>]     # AC voltage measurement
  :CURRent
    :DC? [@<list>]     # DC current measurement
    :AC? [@<list>]     # AC current measurement
  :RESistance? [@<list>]  # 2-wire resistance
  :FRESistance? [@<list>] # 4-wire resistance
  :FREQuency? [@<list>]   # Frequency measurement

CONFigure
  :VOLTage
    :DC [<range>[,<resolution>]] [@<list>]
    :AC [<range>[,<resolution>]] [@<list>]
  :CURRent
    :DC [<range>[,<resolution>]] [@<list>]
    :AC [<range>[,<resolution>]] [@<list>]

TRIGger
  :SOURce <source>     # IMM, EXT, BUS, TIM
  :DELay <seconds>     # Trigger delay
  :COUNt <count>       # Number of triggers

SAMPle
  :COUNt <count>       # Readings per trigger

READ?                  # Initiate + fetch measurement
INITiate              # Initiate trigger system
FETCh?                # Fetch last measurement (no new trigger)