Skip to content

Dropped CAN frames using Socketcan on Raspberry Pi #474

Closed
@Lauszus

Description

@Lauszus

I'm using this library for logging data sent on a CAN-Bus running at 500 kbit/s. The data is sent roughly at 1 kHz.

I have set up a CAN Notifier to receive the data in a thread and the data is then written to a queue in a listener:

class LoggerBufferedListener(can.Listener):
    def __init__(self, log_opened_event: Event):
        self._log_opened_event = log_opened_event
        self._buffer = Queue()
        self._lock = Lock()
        self._closed = False

    def set_closed(self, closed):
        with self._lock:
            self._closed = closed

    def is_closed(self):
        with self._lock:
            return self._closed

    def on_message_received(self, msg: can.Message):
        # Only put the CAN-Bus message into the buffer if it is a close/open command or we are currently logging data
        # and the arbitration ID matches any of the logger IDs
        if msg.arbitration_id == CANLogger.ID_CLOSE_OPEN or \
                (self._log_opened_event.is_set() and
                 msg.arbitration_id in [logger['id'] for logger in CANLogger.Loggers]):
            self.put_nowait(msg)

    def get(self):
        return self._buffer.get()

    def get_nowait(self):
        try:
            return self._buffer.get_nowait()
        except queue.Empty:
            return None

    def put(self, item, force=False):
        if not force:
            if self.is_closed():
                return  # Return if the reader is closed

        self._buffer.put(item)

    def put_nowait(self, item):
        if self.is_closed():
            return  # Return if the reader is closed

        try:
            self._buffer.put_nowait(item)
        except queue.Full:
            Logger.exception('LoggerBufferedListener: Buffer is full')

Another thread is doing nothing else than calling the get() method, the messages are then unpacked and converted to SI-units similar to how I did it in the viewer program:

python-can/can/viewer.py

Lines 135 to 159 in 9f6f918

# Unpack the data and then convert it into SI-units
@staticmethod
def unpack_data(cmd, cmd_to_struct, data): # type: (int, Dict, bytes) -> List[Union[float, int]]
if not cmd_to_struct or len(data) == 0:
# These messages do not contain a data package
return []
for key in cmd_to_struct.keys():
if cmd == key if isinstance(key, int) else cmd in key:
value = cmd_to_struct[key]
if isinstance(value, tuple):
# The struct is given as the fist argument
struct_t = value[0] # type: struct.Struct
# The conversion from raw values to SI-units are given in the rest of the tuple
values = [d // val if isinstance(val, int) else float(d) / val
for d, val in zip(struct_t.unpack(data), value[1:])]
else:
# No conversion from SI-units is needed
struct_t = value # type: struct.Struct
values = list(struct_t.unpack(data))
return values
else:
raise ValueError('Unknown command: 0x{:02X}'.format(cmd))

The data is then written to RAM. After the logged is closed the data is then stored in an Influx database.

However it seems that messages are dropped somewhere, as the data often has gaps in it.

I'm using a MCP2515 and have enabled it using the following overlays in /boot/config.txt:

dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=12
dtoverlay=spi0-hw-cs

My question is basically if anyone has any experience using Socketcan on a Raspberry Pi. Do you guys believe it's a hardware or software issue? I've considered using a different CAN tranceiver than the MCP2515 just to check if that is the culprit. If that does not work I might try to implement the logging in C instead, but would prefer to use Python, as that makes all the parsing of data and writing to the database much easier.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions