Sterowanie cyfrowe przez port RS-485
Podłączenie falownika z komputerem jest widoczne na zdjęciach. Wystarczą do tego zadania dwa przewody. Następnie musimy zadbać o takie samo ustawienie parametrów transmisji po obu stronach.
| Parametr | Wartość | Opis |
|---|---|---|
| PD001 | 2 | Niezbędne do starowania, ale jeśli chcemy tylko monitorować prace to możemy sterować inaczej |
| PD002 | 2 | Kto kontroluje obroty |
| PD163 | 1 | Ustalamy adres urządzenia |
| PD164 | 2 | Prędkość 19200 b/s |
| PD164 | 3 | Tryb RTU |
Konieczne może okazać się również ręczne doinstalowanie zależności
pip install crcmod
pip install pyserial
Moduł do budowania komunikatów
Poniżej przykład użycia prostego modułu do komunikacji z inverter. Ten kod jest dostępny w dedykowanym repozytorium GitHub.
import serial
import time
import HuanyangDev
dev = HuanyangDev.HuanyangDev({"port": "COM5", "rate": 19200, "parity": serial.PARITY_NONE, "address": 1, "timeout": 0.1})
dev.open()
dev.write_function_data(8, 2200)
pd008 = dev.read_function_data(8)
print("PD008 = {}".format(pd008))
dev.write_freq(200)
dev.write_control_data(0x03) # start
# 0: target frequency, 1: output frequency, 2:output current, 3: rpm, 4: DC voltage, 5: AC voltage,6:cont, 7:temp
f1, f2 = dev.read_control_data(0), dev.read_control_data(1)
print("target frequency = {} output frequency = {}".format(f1, f2))
time.sleep(5)
dev.write_control_data(0x08) # stop
dev.close()
import crcmod
import serial
import struct
_crc16 = crcmod.predefined.mkPredefinedCrcFun('modbus')
class HuanyangDev:
def __init__(self, config):
self.config = config
self.conn = None
def open(self):
self.conn = serial.Serial(
port=self.config["port"],
baudrate=self.config["rate"],
parity=self.config["parity"],
timeout=self.config["timeout"]
)
def close(self):
self.conn.close()
def _build_packet(self, function, data):
packet = [self.config["address"], function, len(data)]
packet.extend(data)
crc = self._hy_crc(packet)
packet.extend(crc)
return packet
@staticmethod
def _hy_crc(message):
return list(struct.pack('<H', _crc16(bytes(message))))
def _check_crc(self, message):
if len(message) > 5:
calc_crc = self._hy_crc(message[:-2])
msg_crc = list(message[-2:])
return calc_crc == msg_crc
return False
def _check_msg(self, message):
if self._check_crc(message):
if int(message[1]) & 0xF0 > 0:
return False
return int(message[2]) == len(message[3:-2])
return False
def read_function_data(self, parameter):
packet = self._build_packet(0x01, [parameter])
self.conn.write(bytes(packet))
ans = self.conn.read(8)
if not self._check_msg(ans):
return None
data = ans[3:-2]
value = int.from_bytes(bytes(data[1:]), byteorder='big')
return value
def write_function_data(self, parameter, value):
value = int(value)
value_length = max(1, (value.bit_length() + 7) // 8)
pdata = [parameter]
pdata.extend(list(value.to_bytes(value_length, 'big')))
packet = self._build_packet(0x02, pdata)
self.conn.write(bytes(packet))
ans = self.conn.read(8)
if self._check_msg(ans):
rdata = ans[3:-2]
value = int.from_bytes(bytes(rdata[1:]), byteorder='big')
return value
return None
def write_control_data(self, data):
packet = self._build_packet(0x03, [data])
self.conn.write(bytes(packet))
ans = self.conn.read(6)
if self._check_msg(ans):
value = int.from_bytes(bytes(ans[3:-2]), byteorder='big')
return value
return None
def read_control_data(self, parameter):
packet = self._build_packet(0x04, [parameter])
self.conn.write(bytes(packet))
ans = self.conn.read(8)
if not self._check_msg(ans):
return None
rdata = ans[3:-2]
value = int.from_bytes(bytes(rdata[1:]), byteorder='big')
return value
def write_freq(self, freq):
pdata = list(int(freq * 100).to_bytes(2, 'big'))
packet = self._build_packet(0x05, pdata)
self.conn.write(bytes(packet))
ans = self.conn.read(8)
if self._check_msg(ans):
value = int.from_bytes(bytes(ans[3:-2]), byteorder='big')
ret = value / 100
return ret
return None
Wykorzystanie pyHYControl
Do komunikacji z inverterem możemy wykorzystać moduł pythona pyHYControl, jego wykorzystanie znacznie ułatwi nam życie. Przed przystąpieniem do pracy musimy dołączyć moduł pyHYControl do naszego projektu, niestety pakiet Pip nie jest na chwilę obecną dostępny. Moduł pyHYControl jest przydatny, ale nie idealny.
Praca z konsoli
Sprawdzenie statusu falownika i parametrów chwilowych takich jak:
- obroty chwilowe
- częstotliwość oczekiwana i aktualnie generowana
- napięcie wyjściowe i wejściowe
- prąd pobierany przez silnik
Jeśli parametr PD002 będzie miał wartość równą 2 wówczas możemy zdalnie sterować urządzeniem, zapisywać wartości parametrów konfiguracyjnych oraz wydawać polecenia START, STOP.
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 status rpm
rpm: 1980.00 rpm
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 status vac
vac: 89.30 V
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 status all
fset: 33.00 Hz
fout: 33.00 Hz
aout: 4.70 A
rpm: 1980.00 rpm
vdc: 322.20 V
vac: 23.40 V
cont: 0.00 h
temp: 0.00 C
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 frequency 20
Set frequency command: 20.0
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 frequency 40
Set frequency command: 40.0
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 read 008
read: PD008: 220.0 V
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 write 008 190
written: PD008: 190.0 V
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 read 008
read: PD008: 190.0 V
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 cmd run_fwd
Command: ['run', 'forward']
Status: []
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 cmd run_rev
Command: ['run', 'reverse']
Status: ['cmd_run', 'running']
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 cmd status
Command: []
Status: ['cmd_run', 'cmd_reverse', 'running', 'run_reverse']
D:\Huanyang>python -m hycontrol -d COM5 -p N -b 19200 -a 1 cmd stop
Command: ['stop']
Status: ['cmd_run', 'running']
Przykładowe skrypty
Przykładowe skrypty python do komunikacji z falownikiem Huanyang. Pierwszy dokonuje zrzutu parametrów, kolejny uruchamia falownik, ustawia generowaną częstotliwość, a następnie wyświetla aktualne obroty oraz pobierany prąd.
from hycontrol import VFDConf, RegisterMap, VFDDevice
import os
conf = VFDConf(port="COM5", rate=19200, parity="N", address=1, timeout=0.1)
regmap = RegisterMap(
os.path.join(os.path.dirname(os.path.realpath(__file__)), 'hycontrol', 'registers.yml'))
d = VFDDevice(conf, regmap)
d.connect()
data_to_read = []
data_to_read.extend(range(1, 12))
data_to_read.extend(range(70, 75))
data = {}
for a in data_to_read:
data[a] = d.read_function_data(a)
for k in data:
print("PD{:03d} = {}".format(k, data[k]))
d.close()
from hycontrol import VFDConf, RegisterMap, VFDDevice
import os
import _thread
conf = VFDConf(port="COM5", rate=19200, parity="N", address=1, timeout=0.1)
regmap = RegisterMap(
os.path.join(os.path.dirname(os.path.realpath(__file__)), 'hycontrol', 'registers.yml'))
d = VFDDevice(conf, regmap)
d.connect()
commands = {'status': 0x00, 'run_fwd': 0x03, 'run_rev': 0x11, 'stop': 0x08 }
def get_status(dev, cmd):
return dev.read_control_data(cmd)
def report_thread(dev):
import time
while 1:
time.sleep(0.5)
rpm = get_status(dev, 3)
ocur = get_status(dev, 2)
print("speed = {} rpm output current = {:2.2f} A".format(rpm[0], ocur[0]))
def run_spindle(dev):
dev.write_freq(200)
dev.write_control_data(commands['run_fwd'])
_thread.start_new_thread(report_thread, (dev,))
input('Press ENTER to exit\n')
try:
run_spindle(d)
finally:
d.write_control_data(commands['stop'])
d.close()
Set frequency command: 200.0
Command: ['run', 'forward']
Status: []
Press ENTER to exit
speed = 2526 rpm output current = 3.80 A
speed = 5118 rpm output current = 3.50 A
speed = 7710 rpm output current = 3.40 A
speed = 10302 rpm output current = 3.30 A
speed = 12000 rpm output current = 3.20 A
speed = 12000 rpm output current = 3.20 A
speed = 12000 rpm output current = 3.20 A
speed = 12000 rpm output current = 3.20 A
speed = 12000 rpm output current = 3.20 A
Command: ['stop']
Status: ['cmd_run', 'running']
Process finished with exit code 0



