MECCANICA e DINTORNI http://meccanicaedintorni.morpel.it/phpbb/ |
|
Driver per controllo remoto Wabeco http://meccanicaedintorni.morpel.it/phpbb/viewtopic.php?f=12&t=27418 |
Pagina 1 di 1 |
Autore: | Francoleddu [ sab mar 07, 2020 11:27 ] |
Oggetto del messaggio: | Driver per controllo remoto Wabeco |
Ciao a tutti, vorrei condividere un driver che ho scritto e che potrebbe essere utile ad altri. Serve a controllare, da LinuxCNC, il motore principale di una fresa o un tornio Wabeco nella versione 'hs', ovvero equipaggiati di un motore da 2kW invece che quello standard da 1.4kW. Più in generale, per controllare un Varicon ("Three-Phase Motor with Integrated Frequency Converter") della ditta Hanning Elektro-Werke GmbH, che poi sarebbe il motore che entrambe le macchine della Wabeco montano. Premessa: un paio di anni fa ho acquistato una fresa e un tornio Wabeco, entrambi nella versione 'hs'. Dopo aver costruito un sistema per il controllo degli assi per poter utilizzare LinuxCNC (entrambe le macchine erano già dotate di motori passo) e aver installato sul tornio un decoder sull'asse del mandrino (questi potrebbero essere argomenti di altri post; se qualcuno è interessato mi faccia sapere), mi mancava solo realizzare il controllo del motore principale. Il motore Hanning Varicon è dotato di un box di controllo che prevede un deviatore per la selezione del movimento (CW o CCW) e di un potenziometro per l'impostazione della velocità di rotazione. Dal manuale delle macchine ho visto che il controllo della velocità veniva fatto con una tensione da 0 a 10 volt e del movimento con un paio di segnali a 24 volt. Questo però mi avrebbe imposto l'uso di relè e cablaggi a vari fili per selezionare da PC la macchina da controllare e per scegliere la modalità di controllo, manuale o da programma. Una vera scocciatura per un pigro come me! Aprendo il box ho notato con piacere la presenza di un connettore che suggeriva la possibilità di collegamenti esterni. Allegato: Box prima.jpg Ho scritto alla Wabeco che mi ha gentilmente risposto che non aveva niente di più dello schema già presente nei manuali . Allora mi sono messo alla ricerca su Internet e alla fine ho trovato un pdf con le istruzioni:https://www.cncitalia.net/forum/www.gather-industrie.fr/wp-content/uploads/2015/09/Varicon-1.2-BA-OI_65158-NEUE-BAUREIHE-08_2007-engl.pdf da cui ho visto che il motore può essere controllato anche tramite una linea seriale RS485! La ricerca si è orientata quindi a reperire qualcosa di già fatto. Purtroppo con nessun esito! Gli unici driver HAL seriali che si trovano per LinuxCNC sono per variatori di velocità con controllo ModBus. A questo punto ho preso la decisione di scrivermi il driver che mi serviva. Ho selezionato il driver esistente che più si avvicinava alle mie esigenze, ovvero 'Mitsub VFD Driver' per controllo di VFD Mitsubishi, scritto in Python nel 2017 da Chris Morley: http://linuxcnc.org/docs/html/drivers/mitsub_vfd.html e l'ho modificato per adattarsi al protocollo di comunicazione utilizzato dal Varicon. Il collegamento fisico l'ho realizzato utilizzando un semplice cavetto bipolare schermato e un adattatore USB seriale RS485 della Moxa (UPort 1130), mettendo in parallelo le due macchine in modalità 'RS485 a 2 fili'. Fortunatamente i box presenti sulle macchine prevedono dei 'tappi' per uscite di cavi ausiliari, che ho prontamente utilizzato! Allegato: Box dopo.jpg Il drive, scritto in Python, mette a disposizione una serie di 'pin' (do per scontato una conoscenza base dell'HAL di LinuxCNC) di input e di output che permettono il controllo del motore aggiungendo alcune linee al file <xxx>.hal della configurazione utilizzata.Questo è l'elenco dei pin del driver: Codice: Nome pin Tipo Dir Significato Per esempio, il mio file fresa.hal contiene le seguenti linee:---------------- ----- ---- ------------------------------------------------------------- fwd BIT IN Impostare a True per rotazione destrorsa run BIT IN Impostare a True per avviare il motore debug BIT IN Impostare a True per abilitare i messaggi diagnostici enabled BIT IN Impostare a True per abilitare il controllo via RS485 (Reg 000, 001 and 002) monitor BIT IN Impostare a True per abilitare l'aggiornamento continuo dello stato motion-reversed BIT IN Impostare a True se la rotazione del motore e' invertita (es. nella fresa Wabeco) speed-scale FLOAT IN Configurare questo valore per impostare il rapporto di trasmissione meccanico motor-speed-rpm FLOAT IN Modificare questo valore per impostare la velocita' desiderata, in RPM motor-fb-rpm FLOAT OUT Velocita' attuale del motore, in RPM motor-fb-rps FLOAT OUT Velocita' attuale del motore, in RPS motor-amps FLOAT OUT Valore della corrente di assorbimento del motore, in ampere motor-amps-enab BIT IN Impostare a True per aggiornare il valore di 'motor-amps' (quando anche 'monitor' e' True) estop BIT IN Impostare a True per eseguire uno stop di emergenza error-code U32 OUT Valore del codice di errore, quando 'sts-gen-error' e' True sts-temp-warn BIT OUT Avviso di temperatura: 10'C o meno sotto il limite di blocco sts-temp-rise BIT OUT Temperatura dell'inverter in aumento sts-brake-stop BIT OUT Freno motore disattivato (tensione troppo elevata) sts-chopper-on BIT OUT Chopper attivo sts-enabled BIT OUT Abilitazione negata (pin #14 del connettore a 0) sts-clkpuls-on BIT OUT Impulsi di clock attivi sts-gen-error BIT OUT Errore generale (vedi 'error-code') sts-standstill BIT OUT Frequenza 0 / motore fermo sts-speed-ok BIT OUT Velocità impostata raggiunta sts-rot-ccw BIT OUT Direzione di rotazione sinistrorsa (negativa) sts-pwr-115v BIT OUT Alimentazione principale a 115 V sts-pwr-400v BIT OUT Alimentazione principale a 400 V Codice: loadusr -Wn spindle hanning_vfd.py -p /dev/ttyUSB0 spindle=32 Per installare il driver si procede come segue:# ********** mill spindle vfd setup (slave 32) ************* net spindle-vel-cmd-rpm-abs <= motion.spindle-speed-out-abs net spindle-vel-cmd-rpm-abs => spindle.motor-speed-rpm net spindle-enable <= motion.spindle-on net spindle-enable => spindle.run net spindle-cw <= motion.spindle-forward net spindle-cw => spindle.fwd net spindle-at-speed <= spindle.sts-speed-ok net spindle-at-speed => motion.spindle-at-speed net spindle-speed-rps <= spindle.motor-fb-rps net spindle-speed-rps => motion.spindle-speed-in net machine-is-enabled <= motion.motion-enabled net machine-is-enabled => spindle.monitor net machine-is-enabled => spindle.enabled net estop-out <= iocontrol.0.user-enable-out net estop-out => iocontrol.0.emc-enable-in net estop-out => spindle.estop net spindle-error-condition <= spindle.sts-gen-error net spindle-error-code <= spindle.error-code net spindle-current <= spindle.motor-amps # --- config mill spindle pins --- setp spindle.speed-scale 1.46154 # 38/26 setp spindle.debug 0 setp spindle.motor-amps-enab 0 setp spindle.motion-reversed 1 Hardware:
Software:
Codice: ls /dev | grep USB
Codice: echo -n "/dev/";dmesg|grep tty|grep USB|rev|awk '{print $1}'|rev
fresa: Codice: setp spindle.speed-scale 1.46154 tornio:setp spindle.motion-reversed 1 Codice: setp spindle.speed-scale 1 setp spindle.motion-reversed 0 Note aggiuntive: Il Varicon è configurato di default per utilizzare l'indirizzo 32 e un baudrate di 9600. I valori dell'indirizzo possono andare da 32 a 63 e il baudrate massimo è di 19200. Se si collegano più macchine in parallelo, come ho fatto io, occorre modificare gli indirizzi in modo che siano tutti diversi tra loro! Per il baudrate ho deciso di utilizzare quello di default, ma nel caso si volesse modificare, portandolo a 19200 baud, occorrerà modificarlo sia sulle macchine che specificndolo come parametro sempre nel comando 'loadusr'. Per la modifica dell'indirizzo e/o del baudrate sul Varicon, si deve seguire un procedura un po' più complessa; se qualcuno fosse interessato sono più che disponibile a fornire i dettagli. ------------------------------------------------------------------------------------------------------------------ E finalmente, il driver hanning_vfd.py: Codice: #!/usr/bin/env python # This is a component of linuxcnc # hanning_vfd - Copyright 2020 by Franco Basso # version 1.0 - 2020-03-02 # (based on mitsub_vfd, by Chris Morley) # #---------------------------------------------------------------------------------- # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # #---------------------------------------------------------------------------------- # # LinuxCNC user space component for controlling a Hanning Varicon inverter # over the serial port using RS485 standard; this model of inverter # is integrated in 2kW motors used in Wabeco lathes and mills ('hs' series) # # This driver is based on the Hanning "Varicon Operating Instructions" # manual, version 1.2 (08/2007), 222 pages. # import re import hal import time import serial import traceback SLEEPTIME = 0.03 # delay between tx and rx messages HannReg = { # Varicon registers used by this driver 'mode': 0, 'direction': 1, 'speed_0': 2, 'speed': 3, 'setspeed': 22, 'errorcode': 23, 'status': 51, 'I_motor': 156 } class hanning_serial: def __init__ (self, vfd_names = [['hanning_vfd', '32']], baudrate = 9600, port = '/dev/ttyUSB0'): try: self.ser = serial.Serial ( port, baudrate, parity = serial.PARITY_EVEN, stopbits = serial.STOPBITS_ONE, bytesize = serial.SEVENBITS ) self.ser.timeout = 0.1 self.ser.is_open except: print ('ERROR : hanning_vfd - No serial interface found at {0}'.format (port)) raise SystemExit print ('Hanning VFD serial computer link has loaded') print ('Port: {0},{1},7,E,1'.format (port, baudrate)) self.h = [] self.comp_names = vfd_names for index, name in enumerate (self.comp_names): # print (index, ' NAME:', name[0], ' SLAVE:', name[1]) c = hal.component (name[0]) c.newpin ('fwd', hal.HAL_BIT, hal.HAL_IN) # Set to True for forward motion c.newpin ('run', hal.HAL_BIT, hal.HAL_IN) # Set to True to start the spindle c.newpin ('debug', hal.HAL_BIT, hal.HAL_IN) # Set to True to enable debug output messages c.newpin ('enabled', hal.HAL_BIT, hal.HAL_IN) # Set to True to enable spindle control via RS485 (Reg 000, 001 and 002) c.newpin ('monitor', hal.HAL_BIT, hal.HAL_IN) # Set to True to enable continuous status polling c.newpin ('motion-reversed', hal.HAL_BIT, hal.HAL_IN) # Set to True if the spindle motion is reversed (i.e. in Wabeco mills) c.newpin ('speed-scale', hal.HAL_FLOAT, hal.HAL_IN) # Configure this to set the ratio of mechanical transmission c.newpin ('motor-speed-rpm', hal.HAL_FLOAT, hal.HAL_IN) # Modify this to set the desired spindle speed, in RPM c.newpin ('motor-fb-rpm', hal.HAL_FLOAT, hal.HAL_OUT) # Value of actual spindle speed, in RPM c.newpin ('motor-fb-rps', hal.HAL_FLOAT, hal.HAL_OUT) # Value of actual spindle speed, in RPS c.newpin ('motor-amps', hal.HAL_FLOAT, hal.HAL_OUT) # Value of motor current, in ampere c.newpin ('motor-amps-enab', hal.HAL_BIT, hal.HAL_IN) # Set to True to poll for 'motor-amps' value (when 'monitor' is True) c.newpin ('estop', hal.HAL_BIT, hal.HAL_IN) # Set to True to do an emergecy stop c.newpin ('rx-error-cnt', hal.HAL_U32, hal.HAL_IO) # Number of communication errors c.newpin ('error-code', hal.HAL_U32, hal.HAL_OUT) # Value of error code, when 'sts-gen-error' is True c.newpin ('sts-temp-warn', hal.HAL_BIT, hal.HAL_OUT) # Temperature warning: 10'C or less below shutdown temperature c.newpin ('sts-temp-rise', hal.HAL_BIT, hal.HAL_OUT) # Temperature rise inverter c.newpin ('sts-brake-stop', hal.HAL_BIT, hal.HAL_OUT) # Brake ramp stopped (voltage too high) c.newpin ('sts-chopper-on', hal.HAL_BIT, hal.HAL_OUT) # Chopper active c.newpin ('sts-enabled', hal.HAL_BIT, hal.HAL_OUT) # Enable issued c.newpin ('sts-clkpuls-on', hal.HAL_BIT, hal.HAL_OUT) # Clock pulse turned on c.newpin ('sts-gen-error', hal.HAL_BIT, hal.HAL_OUT) # General error (see 'error-code') c.newpin ('sts-standstill', hal.HAL_BIT, hal.HAL_OUT) # Frequency 0 / standstill c.newpin ('sts-speed-ok', hal.HAL_BIT, hal.HAL_OUT) # Setspeed attained c.newpin ('sts-rot-ccw', hal.HAL_BIT, hal.HAL_OUT) # Direction of rotation counter-clockwise (negative) c.newpin ('sts-pwr-115v', hal.HAL_BIT, hal.HAL_OUT) # Device for 115 V mains voltage c.newpin ('sts-pwr-400v', hal.HAL_BIT, hal.HAL_OUT) # Device for 400 V mains voltag # set reasonable defaults c['fwd'] = True c['run'] = False c['debug'] = False c['enabled'] = False c['monitor'] = False c['motion-reversed'] = False c['motor-speed-rpm'] = False c['motor-amps-enab'] = False c['estop'] = False c['speed-scale'] = 1 c['rx-error-cnt'] = 0 # flags for each device self['last_enabled%d'%index] = c['enabled'] self['last_run%d'%index] = c['run'] self['last_fwd%d'%index] = c['fwd'] self['last_cmd%d'%index] = c['motor-speed-rpm'] self['last_monitor%d'%index] = c['monitor'] self['last_estop%d'%index] = c['estop'] self['last_enq_code%d'%index] = 0 #add device to component reference variable self.h.append (c) print ('Hanning {0} VFD: slave# {1} added'.format (name[0], name[1])) # only issue ready when all the components are ready for i in self.h: i.ready () def loop (self): global SLEEPTIME, HannReg while 1: try: for index, ids in enumerate (self.comp_names): self.slave_num = int (ids[1]) # MONITOR for up-to-speed (sts-speed-ok), alarms and running frequency # 51 is the address for 13 status bits ( b0 - b12 ) if self.h[index]['monitor']: # empty the rx buffer while self.ser.in_waiting > 0: raw = self.ser.read (1) # build the message with the status enquiry msg = self.prepare_enquiry (index, HannReg['status']) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) # and sends it self.ser.write (msg) # wait for the response time.sleep (SLEEPTIME) resp_ok, value, resp = self.poll_output (index) if self.h[index]['debug']: print ('DEBUG: Rx ' + repr (resp)) if resp_ok: # print (value) # decode the status word try: binary = '{0:#015b}'.format (value, 10) except: binary = '0b0000000000000' self.h[index]['sts-temp-warn'] = ((int (binary, 2) & 2) != 0) self.h[index]['sts-temp-rise'] = ((int (binary, 2) & 4) != 0) self.h[index]['sts-brake-stop'] = ((int (binary, 2) & 8) != 0) self.h[index]['sts-chopper-on'] = ((int (binary, 2) & 16) != 0) self.h[index]['sts-enabled'] = ((int (binary, 2) & 32) != 0) self.h[index]['sts-clkpuls-on'] = ((int (binary, 2) & 64) != 0) self.h[index]['sts-gen-error'] = ((int (binary, 2) & 128) != 0) self.h[index]['sts-standstill'] = ((int (binary, 2) & 256) != 0) self.h[index]['sts-speed-ok'] = ((int (binary, 2) & 512) != 0) self.h[index]['sts-rot-ccw'] = ((int (binary, 2) & 1024) != 0) self.h[index]['sts-pwr-115v'] = ((int (binary, 2) & 2048) != 0) self.h[index]['sts-pwr-400v'] = ((int (binary, 2) & 4096) != 0) # if error, reads the error code if self.h[index]['sts-gen-error']: msg = self.prepare_enquiry (index, HannReg['errorcode']) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp_ok, value, resp = self.poll_output (index) if self.h[index]['debug']: print ('DEBUG: Rx ' + repr (resp)) if resp_ok: # Code Error description # 0: No ERROR # 1: Undervoltage error # 2: Overvoltage error # 4: Inverter overtemperature error # 5: Motor overtemperature error # 6: Fan overtemperature error # 8: EEPROM error # 9: Inverter peak current error # 10: Inverter overcurrent error # 11: Inverter continuous current error # 12: Motor overcurrent error # 16: Enable error # 64: Short-circuit error # 128: Power On error # 250: Watch Dog error # 255: Timeout error self.h[index]['error-code'] = int (value) else: # 256: Communication error self.h[index]['error-code'] = 256 else: # 0: No ERROR self.h[index]['error-code'] = 0 # gets the running motor speed status if self.h[index]['sts-standstill']: self.h[index]['motor-fb-rpm'] = 0.0 self.h[index]['motor-fb-rps'] = 0.0 else: msg = self.prepare_enquiry (index, HannReg['speed']) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp_ok, value, resp = self.poll_output (index) if self.h[index]['debug']: print ('DEBUG: Rx ' + repr (resp)) if resp_ok: if self.h[index]['motion-reversed']: value = -value self.h[index]['motor-fb-rpm'] = int (value * self.h[index]['speed-scale']) self.h[index]['motor-fb-rps'] = self.h[index]['motor-fb-rpm'] / 60.0 if self.h[index]['debug'] and 1 == 2: print ('monitor frequency:', value, string, string[3:7], len (string)) # gets the motor current (amps) if self.h[index]['motor-amps-enab']: msg = self.prepare_enquiry (index, HannReg['I_motor']) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp_ok, value, resp = self.poll_output (index) if self.h[index]['debug']: print ('DEBUG: Rx ' + repr (resp)) if resp_ok: self.h[index]['motor-amps'] = value * 0.1 if self.h[index]['debug'] and 1 == 2: print ('monitor amps:', value, string, string[3:7], len (string)) # stop on ESTOP # if ESTOP is false it stops the output # when ESTOP is reset the run command must be re-issued (cycled false to true) to start motor if not self['last_estop%d'%index] == self.h[index]['estop']: if not self.h[index]['estop']: msg = self.prepare_select (HannReg['mode'], 0) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) self['last_run%d'%index] = self.h[index]['run'] = False msg = self.prepare_select (HannReg['setspeed'], 7) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) self['last_enabled%d'%index] = self.h[index]['enabled'] = False self['last_estop%d'%index] = self.h[index]['estop'] print ('**** Hanning VFD: {0} stopped due to Estop Signal'.format (ids[0])) continue print ('**** Hanning VFD: Estop cleared - Must re-issue run command to start {0}.'.format (ids[0])) self['last_estop%d'%index] = self.h[index]['estop'] # set input mode if not self['last_enabled%d'%index] == self.h[index]['enabled']: if self.h[index]['enabled']: msg = self.prepare_select (HannReg['errorcode'], 0) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) if self.h[index]['debug']: print ('DEBUG: Rx ' + resp) time.sleep (SLEEPTIME) data = 0 # Regs 000, 001 and 002 controlled by PC via RS485 link else: data = 7 # Regs 000, 001 and 002 controlled by manual switch and pot knob msg = self.prepare_select (HannReg['setspeed'], data) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) self['last_enabled%d'%index] = self.h[index]['enabled'] if self.h[index]['debug']: print ('DEBUG: Rx ' + resp) # set run if not self['last_run%d'%index] == self.h[index]['run']: if self.h[index]['run']: if self.h[index]['fwd']: data = 1 # forward (CW) else: data = 0 # backward (CCW) if self.h[index]['motion-reversed']: data = 1 - data msg = self.prepare_select (HannReg['direction'], data) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) self['last_fwd%d'%index] = self.h[index]['fwd'] if self.h[index]['debug']: print ('DEBUG: Rx ' + resp) data = 1 # run else: data = 0 # stop msg = self.prepare_select (HannReg['mode'], data) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) self['last_run%d'%index] = self.h[index]['run'] if self.h[index]['debug']: print ('DEBUG: Rx ' + resp) # set direction if not self['last_fwd%d'%index] == self.h[index]['fwd']: if self.h[index]['fwd']: data = 1 # forward (CW) else: data = 0 # backward (CCW) if self.h[index]['motion-reversed']: data = 1 - data msg = self.prepare_select (HannReg['direction'], data) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) self['last_fwd%d'%index] = self.h[index]['fwd'] if self.h[index]['debug']: print ('DEBUG: Rx ' + resp) # set speed if not self['last_cmd%d'%index] == self.h[index]['motor-speed-rpm']: rpm = int (abs (self.h[index]['motor-speed-rpm']) / self.h[index]['speed-scale']) self['last_cmd%d'%index] = self.h[index]['motor-speed-rpm'] msg = self.prepare_select (HannReg['speed_0'], rpm) if self.h[index]['debug']: print ('DEBUG: Tx ' + repr (str (msg))) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) if self.h[index]['debug']: print ('DEBUG: Rx ' + resp) except KeyboardInterrupt: self.kill_output () raise except: print ('error', ids) print (sys.exc_info ()[0]) print ('Loop end!') def kill_output (self): global SLEEPTIME, HannReg for index, ids in enumerate (self.comp_names): # stop the motion self.slave_num = int (ids[1]) time.sleep (SLEEPTIME) msg = self.prepare_select (HannReg['mode'], 0) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) time.sleep (SLEEPTIME) # reset to manual control msg = self.prepare_select (HannReg['setspeed'], 7) self.ser.write (msg) time.sleep (SLEEPTIME) resp = self.poll_acknak (index) print ('Hanning VFD: Kill-> ' + ids[0]) # build the 'enquiry' message (to read a Varicon register) def prepare_enquiry (self, index, code = 51): self['last_enq_code%d'%index] = code converted_data = bytearray (chr (0x04) + chr (self.slave_num) + '{:03}'.format(code) + chr (0x05), 'utf8') return converted_data # build the 'select' message (to modify a Varicon register) def prepare_select (self, code, data): textval = '{:03}={}\x03'.format (code, data) s = 0 for i in range (0, len (textval)): s = s ^ ord (textval[i]) converted_data = bytearray(chr (0x04) + chr (self.slave_num) + chr (0x02) + textval + chr (s), 'utf8') return converted_data # decode the 'enquiry' response def poll_output (self, index): code = value = 0 ok = False resp = raw = self.ser.read (1) if raw == '\x02': core = self.ser.read_until ('\x03', 12) resp += core if core[-1] == '\x03': # message received, check BCC bcc = self.ser.read (1) resp += bcc s = 0 for i in range (0, len (core)): s = s ^ ord (core[i]) if ord (bcc[0]) == s: # BCC ok, message valid mtch = re.match ('([0-9]+)=(-?[0-9]+)\x03', core) if mtch != None: # extract code and value code = int (mtch.group(1)) if code == self['last_enq_code%d'%index]: value = int (mtch.group(2)) ok = True return ok, value, resp self.h[index]['rx-error-cnt'] += 1 return ok, value, resp # decode the 'select' response def poll_acknak (self, index): resp = b'' res = 'err' while self.ser.in_waiting > 0: resp += self.ser.read (1) if len (resp) > 0: if resp[0] == '\x06': return 'ack' elif resp[0] == '\x15': res = 'nak' self.h[index]['rx-error-cnt'] += 1 return res def __getitem__ (self, item): return getattr (self, item) def __setitem__ (self, item, value): return setattr (self, item, value) if __name__ == '__main__': import getopt, sys letters = 'p:b:h' # the : means an argument needs to be passed after the letter keywords = ['port = ', 'baud = '] # the = means that a value is expected after the keyword try: # starts at the second element of argv since the first one is the script name # extraparms are extra arguments passed after all option/keywords are assigned # opts is a list containing the pair 'option'/'value' opts, extraparam = getopt.getopt (sys.argv[1:], letters, keywords) except getopt.GetoptError as err: # print help information and exit: print str(err) # will print something like "option -a not recognized" print ('Use --help option to get help') sys.exit(0) port = '/dev/ttyUSB0' device_ids = [] baud = 9600 for o, p in opts: if o in ['-p', '--port']: port = p elif o in ['-b', '--baud']: baud = p elif o in ['-h', '--help']: print ('Hanning VFD computer-link interface') print (' LinuxCNC user space component for controlling a Hanning Varicon inverter') print (' over the serial port using RS485 standard;') print (' this inverter is used in Wabeco lathes and mills using 2kW motors') print ('') print (''' Sample LinuxCNC code (in <filename>.hal file) loadusr -Wn spindle hanning_vfd -p /dev/tty0 spindle=32 # ********** mill spindle vfd setup (slave 32) ************* net spindle-vel-cmd-rpm-abs <= motion.spindle-speed-out-abs net spindle-vel-cmd-rpm-abs => spindle.motor-speed-rpm net spindle-enable <= motion.spindle-on net spindle-enable => spindle.run net spindle-cw <= motion.spindle-forward net spindle-cw => spindle.fwd net spindle-brake <= motion.spindle-brake net spindle-position => motion.spindle-revs net spindle-at-speed <= spindle.sts-speed-ok net spindle-at-speed => motion.spindle-at-speed net spindle-speed-rps <= spindle.motor-fb-rps net spindle-speed-rps => motion.spindle-speed-in net spindle-index-enable <=> motion.spindle-index-enable net machine-is-enabled <= motion.motion-enabled net machine-is-enabled => spindle.monitor net machine-is-enabled => spindle.enabled net estop-out <= iocontrol.0.user-enable-out net estop-out => iocontrol.0.emc-enable-in net estop-out => spindle.estop net spindle-error-condition <= spindle.sts-gen-error net spindle-error-code <= spindle.error-code net spindle-current <= spindle.motor-amps # --- config mill spindle pins --- setp spindle.speed-scale 1.46154 setp spindle.debug 0 setp spindle.motor-amps-enab 0 setp spindle.motion-reversed 1 ''') sys.exit (0) if extraparam: for dids in extraparam: device_ids.append (dids.split ('=')) else: device_ids = [['hanning_vfd', '32']] # info gathered, now use them try: app = hanning_serial (vfd_names = device_ids, baudrate = int (baud), port = port) app.loop () except KeyboardInterrupt: sys.exit (0) else: exc_type, exc_value, exc_traceback = sys.exc_info () formatted_lines = traceback.format_exc ().splitlines () print ('') print ('**** hanning_vfd debugging:', formatted_lines[0]) traceback.print_tb (exc_traceback, limit = 1, file = sys.stdout) print (formatted_lines[-1]) P.S. nelle foto il filo giallo collegato al terminale 12 della morsettiera, deve essere in effetti collegato al terminale 13. Era collegato al 12 di fabbrica per errore: l'ho segnalato alla Wabeco che mi ha confermato che deve in effetti essere collegato al 13! Sono ovviamente a disposizione per chiarimenti e dettagli |
Autore: | onorino [ sab mar 07, 2020 11:29 ] |
Oggetto del messaggio: | Re: Driver per controllo remoto Wabeco |
grazie. |
Autore: | Dasama46 [ sab mar 07, 2020 13:38 ] |
Oggetto del messaggio: | Re: Driver per controllo remoto Wabeco |
Lavoro importante ! Grazie ! |
Autore: | Francoleddu [ sab mar 07, 2020 13:48 ] |
Oggetto del messaggio: | Re: Driver per controllo remoto Wabeco |
E' stato un piacere! E poi sono un fervente sostenitore del software open source! |
Autore: | CARLINO [ sab mar 07, 2020 15:52 ] |
Oggetto del messaggio: | Re: Driver per controllo remoto Wabeco |
Se operi con Linux devi essere per forza un sostenitore ! Il lavoro mi sembra accurato e professionale ( il mio invece è un parere da dilettante avendo poco in simpatia le macchine cnc ) Mi piacerebbe capire se puoi descrivermelo in termini semplici il vantaggio che porta questa modifica. |
Autore: | McMax [ sab mar 07, 2020 16:04 ] |
Oggetto del messaggio: | Re: Driver per controllo remoto Wabeco |
Bel lavoro bravo, un peccato che sia così specifico per le macchine Wabeco... |
Autore: | Francoleddu [ sab mar 07, 2020 16:38 ] |
Oggetto del messaggio: | Re: Driver per controllo remoto Wabeco |
Ciao Carlino, non capisco bene a quale modifica ti riferisci. Se intendi tutto il lavoro in generale, bè, il vantaggio principale, lavorando in modalità cnc e cioè a controllo di programma, è il fatto che il programma stesso può decidere quando attivare la rotazione del mandrino e a quale velocità. Faccio un paio di esempi: 1 - se vuoi eseguire col tornio una lavorazione trasversale a velocità costante(*), per intenderci facendo muovere solo la torretta, il controllo della velocità ti permette di aumentare il numero di giri man mano che ti avvicini all'asse, certo sempre entro i limiti operativi della macchina; 2 - devi eseguire una filettatura su un pezzo, sempre sul tornio; dando i comandi opportuni (comando GCode 76) puoi attivare il movimento dell'utensile in sincrono con la rotazione del pezzo; 3 - con la fresa devi eseguire in sequenza una serie di lavorazioni cnc con lo stesso utensile ma a velocità diverse; se è il programma a gestire il tutto non devi essere tu ogni volta a modificare la velocità, col rischio magari di sbagliarti. Se invece la modifica a cui ti riferisci è quella di aver voluto fare il controllo tramite RS485 invece di portare una tensione 0~10 volt e i segnali di controllo per avviare il motore in un senso o nell'altro, il motivo fondamentale è la semplicità del cablaggio che nel mio caso si raddoppiava dovendo fare la modifica su due macchine. Oltre a ciò ci sono le possibilità aggiunte da un controllo seriale: poter monitorare l'esatta velocità di rotazione, l'avere un feedback di velocità di lavoro raggiunta, poter monitorare altri parametri come temperature varie (attualmente non implementato ma facilmente fattibile), l'assorbimento di corrente, etc. E poi, stavo quasi dimenticando, forse il primo motivo è stato il divertimento e la soddisfazione nel farlo, che credo sia in questo campo il motore principale! (*) chiedo venia per la terminologia poco appropriata: sono un novizio un po' carente nel lessico --------------------------------- Per McMax: quelle avevo! Grazie comunque per l'apprezzamento! |
Pagina 1 di 1 | Tutti gli orari sono UTC +1 ora |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |