You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
8.8 KiB
Markdown
232 lines
8.8 KiB
Markdown
# Monitoring of Electrical and Thermal Parameters in a Metal Part
|
|
# Introduction
|
|
This project aims to implement a data acquisition system for measuring temperature, voltage, and current in a metal part subjected to constant current, with the purpose of analyzing its electrical and thermal behavior in real time.
|
|
# Methodology
|
|
## Representative drawing
|
|
The image shows the parts that make up the experiment.
|
|
|
|

|
|
|
|
## Equipment
|
|
|
|
| Equipment | Model | Description | Pickture |
|
|
|---------|-------------|-------------|----------|
|
|
| Digit Multimeter | M3500A | Multimeter used to measure voltage and current | 
|
|
| Programmable DC Power Supply 0-30 V | PWS4305 | DC supply for powering the Pyrometer | 
|
|
| System DC Power Supply 150 V / 10 A | N5770A | DC source to heat the metal part | 
|
|
| Pyrometer CTLaser LT | OPTCTLLTSF | Pyrometer, temperature sensor | 
|
|
| Hot plate | IKA C-MAG HS7 | Heated bed with temperature control | 
|
|
|
|
## Communication
|
|
To communicate the `Digit Multimeter M3500A` and the `System DC Power Supply 150 V / 10 A` a USB cable was used through the VISA protocol (Virtual Instrument Software Architecture) which is a standard for configuring, programming and debugging instrumentation systems that include GPIB interfaces. To do this, you first have to download the NI-VISA software on the computer you intend to use since Python is used to communicate through the Python wrapper `pyvisa` which requires the real VISA installation on the system. Otherwise an error will be thrown.
|
|
<br>It is installed `pyvisa`:
|
|
|
|
```bash
|
|
pip install pyvisa
|
|
```
|
|
To find out if Pyvisa detects the instruments, run the following code in Python:
|
|
|
|
```python
|
|
import pyvisa
|
|
rm = pyvisa.ResourceManager()
|
|
print(rm.list_resources())
|
|
```
|
|
If a series of codes are displayed in the Terminal, it means the instruments have indeed been detected and are responding with their data. Something like this:
|
|
|
|
```Terminal
|
|
'USB0::0x164E::0x0DAD::TW00013644::INSTR'
|
|
```
|
|
### Communication with the Optris CTlaser pyrometer
|
|
Communication with the Optris CTlaser pyrometer was performed using the sensor's native binary protocol, using the Python programming language and the standard `pyserial` library for access to the COM port (virtual USB RS-232).
|
|
<br>The sensor protocol consists of sending single-byte binary commands and receiving two-byte encoded responses, representing data such as temperature in `uint16` format.
|
|
<br>Libraries used:
|
|
```python
|
|
import serial
|
|
import time
|
|
```
|
|
|communication parameters| |
|
|
---------------------------|----|
|
|
|Baudrate |115200 bps|
|
|
|Bits de datos |8|
|
|
|Paridad |Ninguna|
|
|
|Bits de parada |1|
|
|
|Timeout |1 segundo|
|
|
|
|
### Command to get temperature
|
|
```python
|
|
COMANDO_TEMPERATURA = bytes([0x01])
|
|
```
|
|
This command requests the process temperature (Tprocess). The sensor's response is 2 bytes, which must be interpreted using the following formula:
|
|
```python
|
|
temperatura = ((byte1 * 256 + byte2) - 1000) / 10
|
|
```
|
|
All this information was obtained from the manufacturer's manuals which are attached to this repository.
|
|
|
|
#### Minimum code for pyrometer reading
|
|
```python
|
|
import serial
|
|
import time
|
|
|
|
sensor = serial.Serial('COM9', baudrate=9600, timeout=1)
|
|
time.sleep(2)
|
|
|
|
sensor.write(bytes([0x01])) #Comando para solicitar la temperatura
|
|
time.sleep(0.2)
|
|
respuesta = sensor.read(2)
|
|
|
|
if len(respuesta) == 2:
|
|
byte1, byte2 = respuesta[0], respuesta[1]
|
|
temperatura = ((byte1 * 256 + byte2) - 1000) / 10
|
|
print(f"Temperatura: {temperatura:.1f} °C")
|
|
else:
|
|
print("No se recibió respuesta válida.")
|
|
|
|
sensor.close()
|
|
```
|
|
## Code
|
|
```python
|
|
import tkinter as tk
|
|
from tkinter import messagebox
|
|
import pyvisa
|
|
import time
|
|
import csv
|
|
from datetime import datetime
|
|
import os
|
|
from decimal import Decimal
|
|
import serial
|
|
|
|
PUERTO = 'COM9' #Puerto COM en donde se encuetra el Pyrometer
|
|
BAUDRATE = 115200
|
|
COMANDO_TEMPERATURA = bytes([0x01]) # Según protocolo binario del sensor
|
|
|
|
ID_M3500A = 'USB0::0x164E::0x0DAD::TW00013644::INSTR' #Multimetro
|
|
ID_N5770A = 'USB0::0x0957::0x0807::N5770A-US11M7295J::INSTR' #Fuente
|
|
|
|
rm = pyvisa.ResourceManager()
|
|
|
|
sensor = serial.Serial(
|
|
port=PUERTO,
|
|
baudrate=BAUDRATE,
|
|
bytesize=serial.EIGHTBITS,
|
|
parity=serial.PARITY_NONE,
|
|
stopbits=serial.STOPBITS_ONE,
|
|
timeout=1
|
|
)
|
|
time.sleep(2)
|
|
|
|
try:
|
|
# Conectar al multímetro
|
|
m3500a = rm.open_resource(ID_M3500A)
|
|
m3500a.write('*RST')
|
|
m3500a.write('*CLS')
|
|
m3500a.write("CONF:VOLT:DC 100") # Voltaje DC, rango fijo de 100 V
|
|
m3500a.write("CONF:CURR:DC 10") # Corriente DC, rango fijo de 10 A
|
|
|
|
# Conectar a la fuente de poder
|
|
fuente = rm.open_resource(ID_N5770A)
|
|
fuente.write('*RST')
|
|
fuente.write('*CLS')
|
|
fuente.write('OUTP ON')
|
|
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"Error en la conexión con los instrumentos:\n{e}")
|
|
exit()
|
|
|
|
directorio = "Mediciones"
|
|
os.makedirs(directorio, exist_ok=True)
|
|
|
|
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
|
archivo_csv = os.path.join(directorio, f"mediciones_{timestamp}.csv")
|
|
|
|
with open(archivo_csv, mode='w', newline='') as archivo:
|
|
escritor = csv.writer(archivo)
|
|
escritor.writerow(["Temperatura","Voltaje Medido (V)", "Corriente Medida (A)","Voltaje fuente","Corriente fuente","Fecha"])
|
|
|
|
##################################################### Lectura del multimetro
|
|
def actualizar_lecturas():
|
|
try:
|
|
# === Leer temperatura del sensor ===
|
|
sensor.write(COMANDO_TEMPERATURA)
|
|
time.sleep(0.2)
|
|
respuesta = sensor.read(2)
|
|
|
|
if len(respuesta) == 2:
|
|
byte1, byte2 = respuesta[0], respuesta[1]
|
|
temperatura = ((byte1 * 256 + byte2) - 1000) / 10
|
|
label_temperatura.config(text=f"Temperatura: {temperatura:.1f} °C")
|
|
else:
|
|
temperatura = None
|
|
label_temperatura.config(text="Temperatura: --- °C")
|
|
|
|
m3500a.write('READ?') # Lectura del multimetro
|
|
voltaje = float(m3500a.read().strip())
|
|
label_voltaje.config(text=f"Voltaje DC: {voltaje:.3f} V")
|
|
|
|
fuente.write("VOLT?") # Lectura de la fuente
|
|
voltaje_fuente = float(fuente.read().strip())
|
|
|
|
fuente.write("CURR?")
|
|
corriente_fuente = float(fuente.read().strip())
|
|
|
|
##################################################### Registro en CSV
|
|
fecha_actual = datetime.now().strftime("%H:%M:%S")
|
|
with open(archivo_csv, mode='a', newline='') as archivo:
|
|
escritor = csv.writer(archivo)
|
|
escritor.writerow([temperatura ,voltaje, "", voltaje_fuente, corriente_fuente, fecha_actual])
|
|
|
|
except Exception as e:
|
|
label_temperatura.config(text="Temperatura: Error")
|
|
label_voltaje.config(text="Voltaje DC: Error")
|
|
label_corriente.config(text="Corriente DC: Error")
|
|
print(f"Error al leer: {e}")
|
|
|
|
# Repetir cada 500 ms
|
|
ventana.after(500, actualizar_lecturas)
|
|
|
|
##################################################### Control de fuente
|
|
def aplicar_valores_fuente():
|
|
try:
|
|
v_set = entrada_voltaje.get()
|
|
i_set = entrada_corriente.get()
|
|
|
|
fuente.write(f"VOLT {v_set}")
|
|
fuente.write(f"CURR {i_set}")
|
|
|
|
#messagebox.showinfo("Configuración", "Valores aplicados correctamente.")
|
|
except Exception as e:
|
|
messagebox.showerror("Error", f"No se pudo configurar la fuente:\n{e}")
|
|
|
|
##################################################### Window
|
|
ventana = tk.Tk()
|
|
ventana.title("CONTROL Y MEDICIÓN")
|
|
ventana.geometry("300x250")
|
|
|
|
######## Lecturas
|
|
|
|
label_temperatura = tk.Label(ventana, text="temperaruta: --- °C", font=("Arial", 14))
|
|
label_temperatura.pack(pady=5)
|
|
|
|
label_voltaje = tk.Label(ventana, text="Voltaje DC: --- V", font=("Arial", 14))
|
|
label_voltaje.pack(pady=5)
|
|
|
|
label_corriente = tk.Label(ventana, text="Corriente DC: --- A", font=("Arial", 14))
|
|
label_corriente.pack(pady=5)
|
|
|
|
######## Control de fuente
|
|
|
|
frame_fuente = tk.Frame(ventana)
|
|
frame_fuente.pack(pady=10)
|
|
|
|
tk.Label(frame_fuente, text="Voltaje de salida (V):",font=("Arial",14)).grid(row=0, column=0, padx=5, pady=2)
|
|
entrada_voltaje = tk.Entry(frame_fuente, width=10)
|
|
entrada_voltaje.grid(row=0, column=1)
|
|
entrada_voltaje.bind('<Return>', lambda event: aplicar_valores_fuente())
|
|
|
|
tk.Label(frame_fuente, text="Corriente límite (A):",font=("Arial",14)).grid(row=1, column=0, padx=5, pady=2)
|
|
entrada_corriente = tk.Entry(frame_fuente, width=10)
|
|
entrada_corriente.grid(row=1, column=1)
|
|
entrada_corriente.bind('<Return>', lambda event: aplicar_valores_fuente())
|
|
|
|
actualizar_lecturas()
|
|
ventana.mainloop()
|
|
``` |