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 socket
import json
import time
import pyvisa
import csv
# ------------------------ MULTIMETER (Keithley DMM6500) ------------------------
# Initialize PyVISA Resource Manager
rm = pyvisa.ResourceManager()
multimeter_ip = "10.10.194.26"
# Open connection to the multimeter via TCP/IP
multimeter = rm.open_resource(f"TCPIP0::{multimeter_ip}::inst0::INSTR")
multimeter.timeout = 5000 # Set timeout for multimeter operations to 5 seconds
def configureResistanceMode():
"""Configures the multimeter for continuous resistance measurement."""
try:
multimeter.write("*RST") # Reset the instrument to its default settings
multimeter.write("*CLS") # Clear the event registers and error queue
multimeter.write("SENS:FUNC 'RES'") # Set the measurement function to Resistance
multimeter.write("SENS:RES:RANG:AUTO ON") # Enable auto-ranging for resistance measurements
multimeter.write("SENS:RES:NPLC 1") # Set integration time (Number of Power Line Cycles) to 1 for speed
multimeter.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 1
multimeter.write("TRIG:COUN INF") # Set trigger count to infinite (continuous triggering)
multimeter.write("INIT:CONT ON") # Enable continuous initiation (continuously acquires data)
print("[Multimeter] Continuous resistance mode configured.")
except Exception as e:
print(f"[ERROR] configuring resistance mode: {e}")
def readResistancesDuring(seconds=3):
"""Reads resistance values from the multimeter for a specified duration."""
readings = []
end_time = time.time() + seconds
try:
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"[Multimeter] {value} Ohms")
readings.append(value)
time.sleep(0.5) # Adjust as needed to control polling rate
except Exception as e:
print(f"[ERROR] during continuous reading: {e}")
return readings
def stopContinuousMode():
"""Stops the continuous measurement mode on the multimeter."""
try:
multimeter.write("INIT:CONT OFF") # Disable continuous initiation
multimeter.write("ABORt") # Abort any pending operations
print("[Multimeter] Continuous mode turned off.")
except Exception as e:
print(f"[ERROR] 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"[ROBOT] Movement result: {result}")
if not suc:
print("[ROBOT] Error sending movement command.")
return
while True:
suc, state, _ = sendCMD(sock, "getRobotState")
if state == 0: # State 0 typically means robot is idle/stopped
break
time.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"[ESP32] Command '{command}' sent.")
time.sleep(wait_time) # Wait for ESP32 to process and respond
response = s.recv(1024)
print(f"[ESP32] Response: {response.decode().strip()}")
except Exception as e:
print(f"[ESP32] Error communicating: {e}")
# ------------------------ MAIN EXECUTION ------------------------
if __name__ == "__main__":
robot_ip = "10.10.8.182"
esp32_ip = "10.10.5.113"
# Define robot joint positions
point_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 robot
conSuc, sock = connectETController(robot_ip)
print("[ROBOT] Connection successful:", conSuc)
if conSuc:
# Open CSV file to save measurement results
with 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 necessary
suc, state, _ = sendCMD(sock, "getRobotState")
if state == 4: # State 4 typically indicates an alarm
sendCMD(sock, "clearAlarm")
time.sleep(2)
try:
# Robot movement sequence for IGBT1
moveToPoint(sock, point_home, 30)
moveToPoint(sock, point_igbt1_approach, 15)
moveToPoint(sock, point_igbt1_measurement, 1)
# Configure multimeter for resistance measurement
configureResistanceMode()
# Measurement 1 (R3 + R6) - Assuming this corresponds to a specific test
sendCommandESP32("IGBT1_M1", esp32_ip)
# Read resistances for 5 seconds
r1_readings = readResistancesDuring(seconds=5)
sendCommandESP32("STOP", esp32_ip) # Send STOP to ESP32 after measurement
stopContinuousMode() # Stop continuous mode on multimeter
writer.writerow(["IGBT1", "G-E (R3+R6)", r1_readings[-1] if r1_readings else None])
# Measurement 2 (R1 + R5) - Assuming this corresponds to a specific test
configureResistanceMode() # Reconfigure multimeter for next measurement
sendCommandESP32("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 test
configureResistanceMode() # Reconfigure multimeter for next measurement
sendCommandESP32("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 home
sendCommandESP32("STOP", esp32_ip) # Ensure ESP32 is stopped before moving robot
moveToPoint(sock, point_igbt1_approach, 15)
moveToPoint(sock, point_home, 30)
except KeyboardInterrupt:
print("Movement interrupted by user.")
# Ensure all systems are stopped on interruption
sendCommandESP32("STOP", esp32_ip)
stopContinuousMode()
moveToPoint(sock, point_home, 30) # Move robot to home position
except Exception as e:
print(f"[MAIN ERROR] An unexpected error occurred: {e}")
# Ensure all systems are stopped on error
sendCommandESP32("STOP", esp32_ip)
stopContinuousMode()
moveToPoint(sock, point_home, 30) # Move robot to home position
finally:
# Ensure all systems are stopped and connections closed
sendCommandESP32("STOP", esp32_ip) # Final stop command to ESP32
stopContinuousMode() # Final stop command to multimeter
disconnectETController(sock) # Disconnect robot"