Error code -113 Undefined SCPI header - Page 1
Forum section: electronics / testgear

author: magama
author_rank: Newbie
timestamp: July 24, 2025, 04:56:13 pm
content: Hello everyone,I'm new here to the forum and I'm developing a master's project that involves automating a collaborative robot to perform measurements on PCBAs. Currently, I'm testing the communication between Python, ESP32, the Cobot, and a KEITHLEY DMM6500 multimeter.My problem lies in the communication with the multimeter. I can establish communication, and the multimeter performs the resistance reading, but when Python tries to read the value, an error appears on the multimeter: "error -113 undefined SCPI header, the SCPI command is not correct. verify that you are using the SCPI command Set"I can't figure out what's wrong. Could you please help me? Below is my code:"import socketimport jsonimport timeimport pyvisaimport csv# ------------------------ MULTIMETER (Keithley DMM6500) ------------------------# Initialize PyVISA Resource Managerrm = pyvisa.ResourceManager()multimeter_ip = "10.10.194.26"# Open connection to the multimeter via TCP/IPmultimeter = rm.open_resource(f"TCPIP0::{multimeter_ip}::inst0::INSTR")multimeter.timeout = 5000 # Set timeout for multimeter operations to 5 secondsdef configureResistanceMode():"""Configures the multimeter for continuous resistance measurement."""try:multimeter.write("*RST") # Reset the instrument to its default settingsmultimeter.write("*CLS") # Clear the event registers and error queuemultimeter.write("SENS:FUNC 'RES'") # Set the measurement function to Resistancemultimeter.write("SENS:RES:RANG:AUTO ON") # Enable auto-ranging for resistance measurementsmultimeter.write("SENS:RES:NPLC 1") # Set integration time (Number of Power Line Cycles) to 1 for speedmultimeter.write("TRIG:SOUR IMM") # Set trigger source to immediate (starts measurement as soon as possible)multimeter.write("SAMP:COUN 1") # Set sample count per trigger to 1multimeter.write("TRIG:COUN INF") # Set trigger count to infinite (continuous triggering)multimeter.write("INIT:CONT ON") # Enable continuous initiation (continuously acquires data)print(" Continuous resistance mode configured.")except Exception as e:print(f" configuring resistance mode: {e}")def readResistancesDuring(seconds=3):"""Reads resistance values from the multimeter for a specified duration."""readings = []end_time = time.time() + secondstry:while time.time() < end_time:# Use FETC? to fetch readings from the buffer when INIT:CONT ON is active.# READ? is often used for single measurements or when not in continuous mode.reading_str = multimeter.query("FETC?")value = float(reading_str.strip())print(f" {value} Ohms")readings.append(value)time.sleep(0.5) # Adjust as needed to control polling rateexcept Exception as e:print(f" during continuous reading: {e}")return readingsdef stopContinuousMode():"""Stops the continuous measurement mode on the multimeter."""try:multimeter.write("INIT:CONT OFF") # Disable continuous initiationmultimeter.write("ABORt") # Abort any pending operationsprint(" Continuous mode turned off.")except Exception as e:print(f" stopping continuous mode: {e}")# ------------------------ ROBOT ------------------------def connectETController(ip, port=8055):"""Connects to the ET Robot controller."""sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:sock.connect((ip, port))return (True, sock)except Exception:sock.close()return (False,)def disconnectETController(sock):"""Disconnects from the ET Robot controller."""if sock:sock.close()def sendCMD(sock, cmd, params=None, id=1):"""Sends a JSON-RPC command to the ET Robot controller."""if not params:params = []else:params = json.dumps(params)sendStr = f'{{"method":"{cmd}","params":{params},"jsonrpc":"2.0","id":{id}}}\n'try:sock.sendall(bytes(sendStr, "utf-8"))ret = sock.recv(1024)jdata = json.loads(ret.decode("utf-8"))if "result" in jdata:return (True, json.loads(jdata["result"]), jdata["id"])elif "error" in jdata:return (False, jdata["error"], jdata["id"])else:return (False, None, None)except Exception:return (False, None, None)def moveToPoint(sock, position, speed):"""Moves the robot to a specified joint position at a given speed."""suc, result, id = sendCMD(sock, "moveByJoint", {"targetPos": position, "speed": speed})print(f" Movement result: {result}")if not suc:print(" Error sending movement command.")returnwhile True:suc, state, _ = sendCMD(sock, "getRobotState")if state == 0: # State 0 typically means robot is idle/stoppedbreaktime.sleep(0.2) # Poll robot state every 0.2 seconds# ------------------------ ESP32 ------------------------def sendCommandESP32(command, esp32_ip, port=3333, wait_time=1):"""Sends a command to the ESP32 and waits for a response."""try:with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:s.connect((esp32_ip, port))s.sendall((command + "\n").encode())print(f" Command '{command}' sent.")time.sleep(wait_time) # Wait for ESP32 to process and respondresponse = s.recv(1024)print(f" Response: {response.decode().strip()}")except Exception as e:print(f" Error communicating: {e}")# ------------------------ MAIN EXECUTION ------------------------if __name__ == "__main__":robot_ip = "10.10.8.182"esp32_ip = "10.10.5.113"# Define robot joint positionspoint_home = [0.000, -90.000, 0.000, -90.000, 90.000, 0.000]point_igbt1_approach = [-35.103, -110.685, 108.715, -59.228, 72.368, -100.673]point_igbt1_measurement = [-35.103, -110.713, 111.545, -62.029, 72.368, -100.673]# Connect to the robotconSuc, sock = connectETController(robot_ip)print(" Connection successful:", conSuc)if conSuc:# Open CSV file to save measurement resultswith open("igbt1_measurements.csv", "w", newline="") as csvfile:writer = csv.writer(csvfile)writer.writerow(["IGBT", "Measurement Type", "Value (Ohms)"])# Check robot state and clear alarm if necessarysuc, state, _ = sendCMD(sock, "getRobotState")if state == 4: # State 4 typically indicates an alarmsendCMD(sock, "clearAlarm")time.sleep(2)try:# Robot movement sequence for IGBT1moveToPoint(sock, point_home, 30)moveToPoint(sock, point_igbt1_approach, 15)moveToPoint(sock, point_igbt1_measurement, 1)# Configure multimeter for resistance measurementconfigureResistanceMode()# Measurement 1 (R3 + R6) - Assuming this corresponds to a specific testsendCommandESP32("IGBT1_M1", esp32_ip)# Read resistances for 5 secondsr1_readings = readResistancesDuring(seconds=5)sendCommandESP32("STOP", esp32_ip) # Send STOP to ESP32 after measurementstopContinuousMode() # Stop continuous mode on multimeterwriter.writerow(["IGBT1", "G-E (R3+R6)", r1_readings[-1] if r1_readings else None])# Measurement 2 (R1 + R5) - Assuming this corresponds to a specific testconfigureResistanceMode() # Reconfigure multimeter for next measurementsendCommandESP32("IGBT1_M2", esp32_ip)r2_readings = readResistencesDuring(seconds=5)sendCommandESP32("STOP", esp32_ip)stopContinuousMode()writer.writerow(["IGBT1", "C-E (R1+R5)", r2_readings[-1] if r2_readings else None])# Measurement 3 (R4 + R6) - Assuming this corresponds to a specific testconfigureResistanceMode() # Reconfigure multimeter for next measurementsendCommandESP32("IGBT1_M3", esp32_ip)r3_readings = readResistencesDuring(seconds=5)sendCommandESP32("STOP", esp32_ip)stopContinuousMode()writer.writerow(["IGBT1", "G-C (R4+R6)", r3_readings[-1] if r3_readings else None])# Return robot to approach position and then homesendCommandESP32("STOP", esp32_ip) # Ensure ESP32 is stopped before moving robotmoveToPoint(sock, point_igbt1_approach, 15)moveToPoint(sock, point_home, 30)except KeyboardInterrupt:print("Movement interrupted by user.")# Ensure all systems are stopped on interruptionsendCommandESP32("STOP", esp32_ip)stopContinuousMode()moveToPoint(sock, point_home, 30) # Move robot to home positionexcept Exception as e:print(f"[MAIN ERROR] An unexpected error occurred: {e}")# Ensure all systems are stopped on errorsendCommandESP32("STOP", esp32_ip)stopContinuousMode()moveToPoint(sock, point_home, 30) # Move robot to home positionfinally:# Ensure all systems are stopped and connections closedsendCommandESP32("STOP", esp32_ip) # Final stop command to ESP32stopContinuousMode() # Final stop command to multimeterdisconnectETController(sock) # Disconnect robot"

author: KungFuJosh
author_rank: Super Contributor
timestamp: July 24, 2025, 05:07:56 pm
content: Quote from: magama on July 24, 2025, 04:56:13 pmWelcome to the site. I can't comment on your coding, but that error means the SCPI command is either unrecognized or incorrectly entered/communicated.Have you tested the SCPI command(s) outside of your scripting?Thanks,Josh

author: Rubo
author_rank: Regular Contributor
timestamp: July 24, 2025, 06:02:05 pm
content: You need to isolate which command generates that error.I would issue every command in the chain one by one either with an if - else or a while loop and catch any errors.That should narrow it down.

author: gamalot
author_rank: Super Contributor
timestamp: July 24, 2025, 06:08:32 pm
content: You just need to try those SCPI commands one by one to find the problem.Also, you should learn how to post code in the forum.Code:import socketimport jsonimport timeimport pyvisaimport csv# ------------------------ MULTIMETER (Keithley DMM6500) ------------------------# Initialize PyVISA Resource Managerrm = pyvisa.ResourceManager()multimeter_ip = "10.10.194.26"# Open connection to the multimeter via TCP/IPmultimeter = rm.open_resource(f"TCPIP0::{multimeter_ip}::inst0::INSTR")multimeter.timeout = 5000 # Set timeout for multimeter operations to 5 secondsdef configureResistanceMode():"""Configures the multimeter for continuous resistance measurement."""try:multimeter.write("*RST") # Reset the instrument to its default settingsmultimeter.write("*CLS") # Clear the event registers and error queuemultimeter.write("SENS:FUNC 'RES'") # Set the measurement function to Resistancemultimeter.write("SENS:RES:RANG:AUTO ON") # Enable auto-ranging for resistance measurementsmultimeter.write("SENS:RES:NPLC 1") # Set integration time (Number of Power Line Cycles) to 1 for speedmultimeter.write("TRIG:SOUR IMM") # Set trigger source to immediate (starts measurement as soon as possible)multimeter.write("SAMP:COUN 1") # Set sample count per trigger to 1multimeter.write("TRIG:COUN INF") # Set trigger count to infinite (continuous triggering)multimeter.write("INIT:CONT ON") # Enable continuous initiation (continuously acquires data)print(" Continuous resistance mode configured.")except Exception as e:print(f" configuring resistance mode: {e}")def readResistancesDuring(seconds=3):"""Reads resistance values from the multimeter for a specified duration."""readings = []end_time = time.time() + secondstry:while time.time() < end_time:# Use FETC? to fetch readings from the buffer when INIT:CONT ON is active.# READ? is often used for single measurements or when not in continuous mode.reading_str = multimeter.query("FETC?")value = float(reading_str.strip())print(f" {value} Ohms")readings.append(value)time.sleep(0.5) # Adjust as needed to control polling rateexcept Exception as e:print(f" during continuous reading: {e}")return readingsdef stopContinuousMode():"""Stops the continuous measurement mode on the multimeter."""try:multimeter.write("INIT:CONT OFF") # Disable continuous initiationmultimeter.write("ABORt") # Abort any pending operationsprint(" Continuous mode turned off.")except Exception as e:print(f" stopping continuous mode: {e}")# ------------------------ ROBOT ------------------------def connectETController(ip, port=8055):"""Connects to the ET Robot controller."""sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:sock.connect((ip, port))return (True, sock)except Exception:sock.close()return (False,)def disconnectETController(sock):"""Disconnects from the ET Robot controller."""if sock:sock.close()def sendCMD(sock, cmd, params=None, id=1):"""Sends a JSON-RPC command to the ET Robot controller."""if not params:params = []else:params = json.dumps(params)sendStr = f'{{"method":"{cmd}","params":{params},"jsonrpc":"2.0","id":{id}}}\n'try:sock.sendall(bytes(sendStr, "utf-8"))ret = sock.recv(1024)jdata = json.loads(ret.decode("utf-8"))if "result" in jdata:return (True, json.loads(jdata["result"]), jdata["id"])elif "error" in jdata:return (False, jdata["error"], jdata["id"])else:return (False, None, None)except Exception:return (False, None, None)def moveToPoint(sock, position, speed):"""Moves the robot to a specified joint position at a given speed."""suc, result, id = sendCMD(sock, "moveByJoint", {"targetPos": position, "speed": speed})print(f" Movement result: {result}")if not suc:print(" Error sending movement command.")returnwhile True:suc, state, _ = sendCMD(sock, "getRobotState")if state == 0: # State 0 typically means robot is idle/stoppedbreaktime.sleep(0.2) # Poll robot state every 0.2 seconds# ------------------------ ESP32 ------------------------def sendCommandESP32(command, esp32_ip, port=3333, wait_time=1):"""Sends a command to the ESP32 and waits for a response."""try:with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:s.connect((esp32_ip, port))s.sendall((command + "\n").encode())print(f" Command '{command}' sent.")time.sleep(wait_time) # Wait for ESP32 to process and respondresponse = s.recv(1024)print(f" Response: {response.decode().strip()}")except Exception as e:print(f" Error communicating: {e}")# ------------------------ MAIN EXECUTION ------------------------if __name__ == "__main__":robot_ip = "10.10.8.182"esp32_ip = "10.10.5.113"# Define robot joint positionspoint_home = [0.000, -90.000, 0.000, -90.000, 90.000, 0.000]point_igbt1_approach = [-35.103, -110.685, 108.715, -59.228, 72.368, -100.673]point_igbt1_measurement = [-35.103, -110.713, 111.545, -62.029, 72.368, -100.673]# Connect to the robotconSuc, sock = connectETController(robot_ip)print(" Connection successful:", conSuc)if conSuc:# Open CSV file to save measurement resultswith open("igbt1_measurements.csv", "w", newline="") as csvfile:writer = csv.writer(csvfile)writer.writerow(["IGBT", "Measurement Type", "Value (Ohms)"])# Check robot state and clear alarm if necessarysuc, state, _ = sendCMD(sock, "getRobotState")if state == 4: # State 4 typically indicates an alarmsendCMD(sock, "clearAlarm")time.sleep(2)try:# Robot movement sequence for IGBT1moveToPoint(sock, point_home, 30)moveToPoint(sock, point_igbt1_approach, 15)moveToPoint(sock, point_igbt1_measurement, 1)# Configure multimeter for resistance measurementconfigureResistanceMode()# Measurement 1 (R3 + R6) - Assuming this corresponds to a specific testsendCommandESP32("IGBT1_M1", esp32_ip)# Read resistances for 5 secondsr1_readings = readResistancesDuring(seconds=5)sendCommandESP32("STOP", esp32_ip) # Send STOP to ESP32 after measurementstopContinuousMode() # Stop continuous mode on multimeterwriter.writerow(["IGBT1", "G-E (R3+R6)", r1_readings[-1] if r1_readings else None])# Measurement 2 (R1 + R5) - Assuming this corresponds to a specific testconfigureResistanceMode() # Reconfigure multimeter for next measurementsendCommandESP32("IGBT1_M2", esp32_ip)r2_readings = readResistencesDuring(seconds=5)sendCommandESP32("STOP", esp32_ip)stopContinuousMode()writer.writerow(["IGBT1", "C-E (R1+R5)", r2_readings[-1] if r2_readings else None])# Measurement 3 (R4 + R6) - Assuming this corresponds to a specific testconfigureResistanceMode() # Reconfigure multimeter for next measurementsendCommandESP32("IGBT1_M3", esp32_ip)r3_readings = readResistencesDuring(seconds=5)sendCommandESP32("STOP", esp32_ip)stopContinuousMode()writer.writerow(["IGBT1", "G-C (R4+R6)", r3_readings[-1] if r3_readings else None])# Return robot to approach position and then homesendCommandESP32("STOP", esp32_ip) # Ensure ESP32 is stopped before moving robotmoveToPoint(sock, point_igbt1_approach, 15)moveToPoint(sock, point_home, 30)except KeyboardInterrupt:print("Movement interrupted by user.")# Ensure all systems are stopped on interruptionsendCommandESP32("STOP", esp32_ip)stopContinuousMode()moveToPoint(sock, point_home, 30) # Move robot to home positionexcept Exception as e:print(f"[MAIN ERROR] An unexpected error occurred: {e}")# Ensure all systems are stopped on errorsendCommandESP32("STOP", esp32_ip)stopContinuousMode()moveToPoint(sock, point_home, 30) # Move robot to home positionfinally:# Ensure all systems are stopped and connections closedsendCommandESP32("STOP", esp32_ip) # Final stop command to ESP32stopContinuousMode() # Final stop command to multimeterdisconnectETController(sock) # Disconnect robot"

author: magama
author_rank: Newbie
timestamp: July 25, 2025, 03:03:13 pm
content: Thanks for the answer,The resistance reading appears in the multimeter and the values that the multimeter is reading also appear in the VScode terminal.The error message -133 appears on the multimeter screen.The error only appears since I added "def lerResistenciasDurante(seconds=3):"I made a mistake when publishing the code. The code that caused the error is:Code:def configurarModoResistencia():try:multimetro.write("*RST")multimetro.write("*CLS")multimetro.write("SENS:FUNC 'RES'")multimetro.write("SENS:RES:RANG:AUTO ON")multimetro.write("SENS:RES:NPLC 1")multimetro.write("TRIG:SOUR IMM")multimetro.write("SAMP:COUN 1")multimetro.write("TRIG:COUN INF")multimetro.write("INIT:CONT ON")print(" Modo resistência contínua configurado.")except Exception as e:print(f" ao configurar resistência: {e}")def lerResistenciasDurante(segundos=3):leituras = []fim = time.time() + segundostry:while time.time() < fim:leitura = multimetro.query("READ?")valor = float(leitura.strip())print(f" {valor} Ohms")leituras.append(valor)time.sleep(0.5)except Exception as e:print(f" durante leitura contínua: {e}")return leituras

author: TizianoHV
author_rank: Regular Contributor
timestamp: July 25, 2025, 03:18:02 pm
content: When you use "READ?" the multimeter should be in "single shot" mode with: trig count = 1 (not INFinite) and init:cont offCode:def configurarModoResistencia():try:multimetro.write("*RST")multimetro.write("*CLS")multimetro.write("SENS:FUNC 'RES'")multimetro.write("SENS:RES:RANG:AUTO ON")multimetro.write("SENS:RES:NPLC 1")multimetro.write("TRIG:SOUR IMM")multimetro.write("SAMP:COUN 1")multimetro.write("TRIG:COUN 1")multimetro.write("INIT:CONT OFF")print(" Modo resistência contínua configurado.")except Exception as e:print(f" ao configurar resistência: {e}")def lerResistenciasDurante(segundos=3):leituras = []fim = time.time() + segundostry:while time.time() < fim:leitura = multimetro.query("READ?")valor = float(leitura.strip())print(f" {valor} Ohms")leituras.append(valor)time.sleep(0.5)except Exception as e:print(f" durante leitura contínua: {e}")return leituras

author: Rubo
author_rank: Regular Contributor
timestamp: July 25, 2025, 03:38:38 pm
content: Quote from: TizianoHV on July 25, 2025, 03:18:02 pmAgreed. You should use "FETCh?" instead if you want continuous readings.

author: KungFuJosh
author_rank: Super Contributor
timestamp: July 25, 2025, 04:16:34 pm
content: I've not tried with the Keithley, but using the same SCPI logic on the CNT-90 and 53132A, READ? was always better, and to use FETC? required initiating the measurement with 2 or 3 commands. FETC? only gave the last measurement and didn't always give a new reading even in continuous mode. 🤷

author: Rubo
author_rank: Regular Contributor
timestamp: July 25, 2025, 04:57:20 pm
content: Now it's really confusing.In HOIKI programming manual it says that READ initiates a single trigger event and returns the reult of said event, so you have use it with INIT:CONT OFFFETCh does not initiate a trigger event and simply return whatever the last triggered reading was, so you have use it to display results with INIT:CONT ONIn Keysight's programming guide it gives similar explanation, but says you can use READ with INIT:CONT ON

author: KungFuJosh
author_rank: Super Contributor
timestamp: July 25, 2025, 05:24:14 pm
content: I think maybe Hioki has it backwards there since I'm guessing Keithley and Keysight may agree?

author: TizianoHV
author_rank: Regular Contributor
timestamp: July 25, 2025, 10:31:33 pm
content: I have a Keithley 2790 (2000 family) and an Agilent 34970A (similar to 34401A).Keithleys are a bit pickier with their trigger model (you need to "manually" disable INIT cont).The Agilent will enter automatically "remote" mode (so you don't need to send INIT:CONT OFF).

author: magama
author_rank: Newbie
timestamp: July 30, 2025, 01:57:10 pm
content: First of all, I thank you for all the help you gave me. I see that there are some differences between equipment in terms of SCPI commands. I managed to get it working without error, here is the working code. Does it make sense to stay like this?First of all, I thank you for all the help you gave me. I see that there are some differences between equipment in terms of SCPI commands. I managed to get it working without error, here is the working code. Does it make sense?Code:def configurarModoResistencia():def enviar(cmd):try:multimetro.write(cmd)erro = multimetro.query("SYST:ERR?")if not erro.startswith("0"):print(f"[ERRO SCPI] Comando: {cmd} → {erro.strip()}")except Exception as e:print(f"[EXCEÇÃO PYTHON] ao enviar '{cmd}': {e}")try:enviar('FUNCtion "RESistance"')enviar("SENS:RES:RANG:AUTO ON")enviar("SENS:RES:NPLC 1")print("[Keithley DMM6500] Modo resistência configurado.")except Exception as e:print(f" na configuração: {e}")Now I have another challenge which is to read in diode mode

author: Rubo
author_rank: Regular Contributor
timestamp: July 30, 2025, 02:51:07 pm
content: If it's working as expected, sure. I would still issue *RST & *CLS in the beginning of the code, before -> enviar("SENS:RES:RANG:AUTO ON")Have fun

author: TizianoHV
author_rank: Regular Contributor
timestamp: August 18, 2025, 10:07:07 am
content: When you send ""SYST:ERR?" you'll get only the first error (FIFO). If you want to read all errors you should use a while loop (easy fix).