def read_regs(mst: modbus.Instrument, start: int, count: int): return mst.read_registers(start, count)
class RCUModbusAdapter: """ RCU MODBUS interface This is the python class object for Xnergy RCU ROS Driver MODBUS RTU adapter class. RCUModbus Interface python class object require to input serialport to initiate the class object RCUModbusInterface class object generally provide three function: a) Trigger RCU unit to charge through MODBUS RTU b) Trigger RCU unit to discharge through MODBUS RTU c) Trigger RCU unit to update status and capture the information into RCUModbusInterface object variables """ def __init__(self, port="/dev/ttyUSB0", slave_addr=16, baudrate=9600): """ Initialize RCU modbus rtu """ self.is_connected = True self.firmware_version_number = -1 self.runtime_voltage_setting = -1 self.runtime_current_setting = -1 self.charge_status = -1 self.charge_status_message = 'None' self.voltage_conversion = -1 self.current_conversion = -1 self.rcu_lock = Lock() self._baudrate = baudrate self._slave_addr = slave_addr self._port = port self.errors = [] self._previous_shadow_error_high = 0 self._previous_shadow_error_low = 0 def connect(self): try: if(self.is_connected): self._instrument.close() self._instrument = Instrument( port=self._port, mode=MODE_RTU, slaveaddress=self._slave_addr) self._instrument.serial.baudrate = self._baudrate self._instrument.serial.timeout = 1 self._instrument.mode = MODE_RTU # RCU Hardware Setting # Read RCU Hardware Setting # firmware version information firmware_version_number_reg = self._instrument.read_registers(registeraddress=_MODBUS_ADDRESS_FIRMWARE_VERSION_NUMBER, number_of_registers=1, functioncode=_MODBUS_READ_INPUT_REGISTERS) self.firmware_version_number = firmware_version_number_reg[0] # runtime voltage setting information runtime_voltage_setting_reg = self._instrument.read_registers(registeraddress=_MODBUS_ADDRESS_RUNTIME_VOLTAGE_SETTING, number_of_registers=1, functioncode=_MODBUS_READ_HOLDING_REGISTERS) self.runtime_voltage_setting = float( runtime_voltage_setting_reg[0])/128 # runtime currnet setting information runtime_current_setting_reg = self._instrument.read_registers(registeraddress=_MODBUS_ADDRESS_RUNTIME_CURRENT_SETTING, number_of_registers=1, functioncode=_MODBUS_READ_HOLDING_REGISTERS) self.runtime_current_setting = float( runtime_current_setting_reg[0])/128 # Set voltage conversion if self.runtime_voltage_setting > 48.0: self.voltage_conversion = 0.02229 else: self.voltage_conversion = 0.01155 if self.runtime_voltage_setting > 48.0: self.current_conversion = 0.02014 else: self.current_conversion = 0.04028 return True except: self.is_connected = False return False # self._instrument.serial.timeout = 0.4 def enable_charge(self): """ Enable RCU to charge """ return self.write_bit(_MODBUS_ADDRESS_ENABLE_CHARGING, 1) def disable_charge(self): """ Disable RCU to charge """ return self.write_bit(_MODBUS_ADDRESS_ENABLE_CHARGING, 0) def write_bit(self, register_address, input_value): """ Sending command to RCU unit with threading lock to prevent parallel access to interface """ self.rcu_lock.acquire() result = False try: self._instrument.write_bit( registeraddress=register_address, value=input_value) result = True except serial.serialutil.SerialException as e: rospy.logwarn( "Serial exception when writing into a register. %s", str(e)) except (minimalmodbus.NoResponseError, minimalmodbus.InvalidResponseError) as e: rospy.logwarn("%s.", str(e)) self.rcu_lock.release() return result def reset_errors(self): self._previous_shadow_error_low = 0 self._previous_shadow_error_high = 0 def get_rcu_status(self): """ Get charging and hardware information from RCU unit and store the information to RCUModbusInterface object variable """ self.rcu_lock.acquire() # charging status information try: data = self._instrument.read_registers(registeraddress=0, number_of_registers=_MODBUS_NUM_REGISTERS, functioncode=_MODBUS_READ_INPUT_REGISTERS) except serial.serialutil.SerialException as e: rospy.logwarn("Could not read holding register. %s", str(e)) self.charge_status = ChargerState.RCU_NOT_CONNECTED self.charge_status_message = translate_charge_status( self.charge_status) self.rcu_lock.release() return except (minimalmodbus.NoResponseError, minimalmodbus.InvalidResponseError) as e: rospy.logdebug("Invalid Modbus response.") self.charge_status = ChargerState.RCU_NOT_CONNECTED self.charge_status_message = translate_charge_status( self.charge_status) self.rcu_lock.release() return except: rospy.logwarn("Could not read holding register.") self.charge_status = ChargerState.RCU_NOT_CONNECTED self.charge_status_message = translate_charge_status( self.charge_status) self.rcu_lock.release() return charge_status = data[_MODBUS_ADDRESS_CHARGE_STATUS] self.charge_status = charge_status self.charge_status_message = translate_charge_status(charge_status) # rcu device id information self.rcu_device_id = data[_MODBUS_ADDRESS_RCU_DEVICE_ID] # RCU real time error self.errors = [] rcu_error_low = data[_MODBUS_ADDRESS_RCU_ERROR_LOW] if rcu_error_low > 0: for error in rcu_error_data_list: if (rcu_error_low & error): error_msg = translate_error_code(error, 'low') self.errors.append(error_msg) rcu_error_high = data[_MODBUS_ADDRESS_RCU_ERROR_HIGH] if not rcu_error_high > 0: for error in rcu_error_data_list: if (rcu_error_high & error): error_msg = translate_error_code(error, 'high') self.errors.append(error_msg) # Shadow Error shadow_error_low = data[_MODBUS_ADDRESS_SHADOW_ERROR_LOW] # append only new shadow errors to error list new_shadow_error_low = (~self._previous_shadow_error_low ) & shadow_error_low if new_shadow_error_low > 0: for error in rcu_error_data_list: if (new_shadow_error_low & error): error_msg = translate_error_code(error, 'low') self.errors.append(error_msg) self._previous_shadow_error_low = shadow_error_low shadow_error_high = data[_MODBUS_ADDRESS_SHADOW_ERROR_HIGH] # append only new shadow errors to error list new_shadow_error_high = (~self._previous_shadow_error_high ) & shadow_error_high if new_shadow_error_high > 0: for error in rcu_error_data_list: if (new_shadow_error_high & error): error_msg = translate_error_code(error, 'high') self.errors.append(error_msg) self._previous_shadow_error_high = shadow_error_high # output current information output_current = data[_MODBUS_ADDRESS_OUTPUT_CURRENT] self.output_current = float(output_current) * self.current_conversion # battery voltage information battery_voltage = data[_MODBUS_ADDRESS_BATTERY_VOLTAGE] self.battery_voltage = float(battery_voltage) * self.voltage_conversion # RCU Hardware Status variable # device temperature information self.device_temperature = data[_MODBUS_ADDRESS_DEVICE_TEMPERATURE] # coil temperature information self.coil_temperature = data[_MODBUS_ADDRESS_COIL_TEMPERATURE] self.rcu_lock.release()
import sys import time from minimalmodbus import Instrument if __name__ == "__main__": if len(sys.argv) < 2: print 'Usage: %s [COM]' % sys.argv[0] exit(1) port = sys.argv[1] inst = Instrument(port, 1) inst.serial.baudrate = 57600 inst.serial.timeout = 0.1 for i in range(1, 16): try: inst.address = i response = inst.read_registers(0x0001, 1) except IOError: pass else: print hex(response[0]) fw_version = response[0] & 0x0FFF hw_version = response[0] >> 12 print 'Slave {}: FW {:03X}, HW {:01X}'.format(i, fw_version, hw_version) time.sleep(0.01) print 'Done.'
class Slave: def __init__(self, label, slave_id, slave_address, setupsAdr, setupsCount, variablesAdr, variablesCount, port): self.label = label self.id = slave_id self.port = port self.slave_address = slave_address self.setupsAdr = setupsAdr self.setupsCount = setupsCount self.variablesAdr = variablesAdr self.variablesCount = variablesCount try: self.instrument = Instrument(self.port, slave_address) except: self.status = "ERROR" traceback.print_exc() self.status = "NEW" self.variable_values = [] self.config_values = [] def getConfig(self, adr): if self.status == "OK": return self.config_values[adr] else: return 0 def getValue(self, adr): if self.status == "OK": return self.variable_values[adr - self.variablesAdr] else: return 0 def getVariables(self): try: self.variable_values = self.instrument.read_registers( self.variablesAdr, self.variablesCount) self.status = "OK" except IOError: self.status = "ERROR" traceback.print_exc() def getConfigs(self): try: self.config_values = self.instrument.read_registers( self.setupsAdr, self.setupsCount) self.status = "OK" except IOError: self.status = "ERROR" traceback.print_exc() def setConfigs(self): try: #TODO Detener el hilo de actualización de las variables self.instrument.write_registers(self.setupsAdr, self.config_values) self.status = "OK" except IOError: self.status = "ERROR" traceback.print_exc() def run(self): if self.status != "OK": self.getConfigs() self.getVariables() def simulate(self): print('Simulating from slave: %s' % self.id) from random import randint self.variable_values = [ randint(0, 100) for i in range(self.variablesCount) ] self.status = "SIMULATE"
READS = 1000 # Number of registers to be read. REGISTERS = 1 if __name__ == "__main__": if len(sys.argv) < 3: print 'Usage: %s [COM] [SLAVE_ADDRESS]' % sys.argv[0] exit(1) port = sys.argv[1] slave_address = int(sys.argv[2]) inst = Instrument(port, slave_address) inst.serial.baudrate = 57600 inst.serial.timeout = 1 start_time = time.time() for i in range(READS): response = inst.read_registers(0x0000, REGISTERS) if response[0] != 0x0000: print 'IR inputs: {:02X}'.format(response[0]) end_time = time.time() print 'Duration of {} reads from {} register: {:.2f} seconds.'.format( READS, REGISTERS, end_time - start_time, )
import time from minimalmodbus import Instrument if __name__ == "__main__": if len(sys.argv) < 2: print 'Usage: %s [COM]' % sys.argv[0] exit(1) port = sys.argv[1] inst = Instrument(port, 1) inst.serial.baudrate = 57600 inst.serial.timeout = 0.1 for i in range(1, 16): try: inst.address = i response = inst.read_registers(0x0001, 1) except IOError: pass else: print hex(response[0]) fw_version = response[0] & 0x0FFF hw_version = response[0] >> 12 print 'Slave {}: FW {:03X}, HW {:01X}'.format( i, fw_version, hw_version) time.sleep(0.01) print 'Done.'
class Bearing_Serial(QObject): Warning_Signal = pyqtSignal(str) def __init__(self, com, baudrate, serialtype): super(Bearing_Serial, self).__init__() self._port = com self._baudrate = baudrate self._serialtype = serialtype def set_setting(self, com, baudrate, serialtype): self._port = com self._baudrate = baudrate self._serialtype = serialtype def open_serial(self): if (self._serialtype == 'serial'): try: self._serial = Serial() self._serial.port = self._port self._serial.baudrate = self._baudrate self._serial.open() self.Warning_Signal.emit('打开串口成功') return 1 except: self.Warning_Signal.emit('打开串口失败') return 0 elif(self._serialtype == 'modbus'): try: self._serial = Instrument(self._port, 1) self._serial.serial.baudrate = self._baudrate self.Warning_Signal.emit('打开串口成功') return 1 except: self.Warning_Signal.emit('打开串口失败') return 0 def read_data(self, n=0): if (self._serialtype == 'serial'): try: if n > 0: return self._serial.read(n) else: self._serial.reset_input_buffer() data = self._serial.readline() return data except: self.Warning_Signal.emit('读取数据失败,请检查串口!') elif (self._serialtype == 'modbus'): try: data = self._serial.read_registers(0, 8) return data except: self.Warning_Signal.emit('读取数据失败,请检查串口!') def send_data(self, data): if (self._serialtype == 'serial'): self._serial.write(data) def close(self): if (self._serialtype == 'serial'): try: self._serial.close() except IOError: self.Warning_Signal.emit('关闭串口失败') elif (self._serialtype == 'modbus'): pass