3

I am reading values from a Battery Management System using two, serial USB-RS485 adaptors (ftdi). I am doing this over MODBUS using the minimal modbus library and python:

# Bank A
# port name, slave address (in decimal)

instrument_A = minimalmodbus.Instrument('/dev/ttyUSB0', 1)

# Bank B
instrument_B = minimalmodbus.Instrument('/dev/ttyUSB1', 1)
# Port on which to send via serial to CAN Shield Arduino
port = '/dev/ttyACM0'
# Initialize CAN Shield Arduino Serial Line
ard = serial.Serial(port, 115200, timeout=5)
// Read something from BMS
socA = instrument_A.read_register(40008)

See picture below

enter image description here

I am reading these values repeatedly, and then sending them over another serial/UART to an arduino which is then controlling some things..

Now this all works absolutely fine on my laptop, which runs ubuntu - but it only works on the Pi for a few reads, after which it fails.

Is the raspberry pi not capable of doing this many serial concurrent processes at once?

Edit:

I have now included the whole python file, as it has been pointed out that the question was not as clear in terms of what is running concurrently etc.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import minimalmodbus
import serial
import syslog
import time
import math

# Some constants which are decided by us, and are sent to the inverter - not coming from the BMS
CONST_BAT_CHARGE_VOLTAGE    = 585  # 58,5V
CONST_BAT_DISCHARGE_VOLTAGE = 44 * 10
CONST_BAT_CHRGE_CURR_LIM = 50*10   # Battery Rack DC Charge Current Limitation, integer
VAR_BAT_DCHRG_CURR_LIM = 200*10   # Battery Rack DC Discharge Current Limitation, integer



# Looping constants

running = 1
counter = 0

# Some constants which are decided by us, and are sent to the inverter - not coming from the BMS
# Voltage at which battery need be charged. 58,5V

CONST_BAT_CHARGE_VOLTAGE = 585

# Voltage at which the battery stops discharging

CONST_BAT_DISCHARGE_VOLTAGE = 44 * 10

# Battery Rack DC Charge Current Limitation, integer

VAR_BAT_CHRGE_CURR_LIM = 0 * 10

# Battery Rack DC Discharge Current Limitation, integer

CONST_BAT_DCHRG_CURR_LIM = 200 * 10
CONST_BAT_RCK_AVG_SOC = 75  # Battery Rack, average module SOC Value, integer
CONST_BAT_RCK_AVG_SOH = 98  # Battery Rack, average module SOH Value, integer

# Bank A
# port name, slave address (in decimal)

# instrument_A = minimalmodbus.Instrument('/dev/ttyUSB0', 1)
instrument_A = minimalmodbus.Instrument('/dev/cu.lpss-serial1', 1)
# Bank B

instrument_B = minimalmodbus.Instrument('/dev/cu.lpss-serial2', 1)
# Port on which to send via serial to CAN Shield Arduino

# port = '/dev/ttyACM0'
port = '/dev/cu.usbmodem14421'
# Initialize CAN Shield Arduino Serial Line

ard = serial.Serial(port, 115200, timeout=5)


################### FUNCTIONS ###################
# Convert integer to binary string

def int2bin(i):
    if i == 0:
        return '0'
    s = ''
    while i:
        if i & 1 == 1:
            s = '1' + s
        else:
            s = '0' + s
        i /= 2
    return s


# Rounds up to the the ceiling

def ceiling(x):
    n = int(x)
    return (n if n - 1 < x <= n else n + 1)


# To determine the number of bits within a type of object

def bitLen(int_type):
    length = 0
    while int_type:
        int_type >>= 1
        length += 1
    return length


# Convert an integer into the parts of its most and least significant bits

def toHex(x):
    LSB = x & 0x00FF
    MSB = x >> 8
    return (LSB, MSB)


# Get battery data

def getBatteryData(InverterAddress):

    # Initializing send buffer, this buffer is populated with integers - ready for transformation into a byte array

    sendBuffer = []
    if InverterAddress == 0x351:
        sendBuffer.append(1)
        sendBuffer.append(CONST_BAT_CHARGE_VOLTAGE)
        sendBuffer.append(VAR_BAT_CHRGE_CURR_LIM)
        sendBuffer.append(CONST_BAT_DCHRG_CURR_LIM)
        sendBuffer.append(CONST_BAT_DISCHARGE_VOLTAGE)
    elif InverterAddress == 0x355:
        sendBuffer.append(5)

        # Battery Rack A, Average module SOC Value, integer

        socA = instrument_A.read_register(40008)
        socB = instrument_B.read_register(40008)
        soc = ceiling((socA + socB) / 2 / 10)
        sendBuffer.append(soc)
        # print "SOC For Bank A"
        # print socA
        # print "SOC For Bank B"
        # print socB
        # Battery Rack, average module SOH Value, integer
        # print "Average SOC Value, both banks"
        # print soc
        sohA = instrument_A.read_register(40009)
        sohB = instrument_B.read_register(40009)
        soh = ceiling((sohA + sohB) / 2 / 10)
        # print "Average SOH Value, both banks"
        # print soh
        sendBuffer.append(soh)
    elif InverterAddress == 0x35A:
        sendBuffer.append(0x65)
        sendBuffer.append(0)
        sendBuffer.append(0)
    else:
        sendBuffer.append(0)

    byteSendBuffer = bytearray()
    for i in sendBuffer:
        (LSB, MSB) = toHex(i)
        byteSendBuffer.append(LSB)
        byteSendBuffer.append(MSB)

    # print "The following is the byte array to be sent to the Inverter"

    for byte in byteSendBuffer:
        print byte
    return byteSendBuffer


while running:
    print 'Starting read and serial write cycle'

    time.sleep(0.3)
    ard.write(getBatteryData(0x351))
    ard.write(getBatteryData(0x355))
    ard.write(getBatteryData(0x35A))
    # try:
    #     print "Attempting read and send..."
    #     ard.write(getBatteryData(0x351))
    #     ard.write(getBatteryData(0x355))
    #     ard.write(getBatteryData(0x35A))
    # except:
    #     print "Failure..."
    #     pass

    time.sleep(0.3)

    print 'Ending read and serial write cycle'
4
  • This question is likely not answerable as written, since we don't have access to your system. In addition the code as presented shows nothing of the structure of your concurrent processes. Dec 10, 2017 at 16:40
  • Thank you, I have added the entire python file, the port names are weird as I was running this version from my mac. I have however run the same file,with linux port names on my linux laptop and it also worked perfectly. Dec 11, 2017 at 7:02
  • I know you did not ask but binary string can be had with "{0:b}".format(an_int_value) Dec 11, 2017 at 14:50
  • I see no concurrent code here. Dec 11, 2017 at 14:51

1 Answer 1

1

Ended up solving it by setting:

minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True

Found this in the minimalmodbus API docs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.