Handling CAN databases in Python

  • February 8, 2018
  • Magnus Carlsson

This is the first post in a 2-part series about how to manage DBC databases using the Kvaser database library (kvadblib) and Python:

  1. Handling CAN databases in Python
  2. Send and receive database signals

With the release of CANlib SDK v5.22, the database library (kvaDbLib) has been overhauled and the Python canlib wrapper package (v1.5) have added support for database handling through the kvadblib module. The kvaDbLib library is used for creating, writing, reading and modifying DBC databases.1 We will in this first post take a look at how to create and examine a DBC database using the Python canlib wrapper package. The Python canlib package is released as a Python Wheel for easy installing using pip install. If you don’t have it installed yet, take a look at the blog post Python samples are now bundled in a package2 for more information on the subject.


Creating a database

A database is used to translate raw CAN data into human readable signals. In this example we’ll work with a hypothetical vehicle database.

Let us get started right away by creating a database from scratch. We begin with importing kvadblib from the canlib python package and create a new database named “Histogram”3 , add a message with id “402”, dlc “8” and name the message “LIM_002”.

from canlib import kvadblib

# Create a new database
db = kvadblib .Dbc(name=’Histogram ’ )

# Add messages
message = db.new_message(name=’LIM_002’ ,
			 id=402,
			 dlc=8)

The next step is to add a signal to the message we just created. Let us add a float signal named “Load” with some unit and comment text.

   message . new_signal(
       name=’Load ’ ,
       type=kvadblib . SignalType .FLOAT,
       byte_order=kvadblib . SignalByteOrder .INTEL, # default
       mode=kvadblib . SignalMultiplexMode .MUX_INDEPENDENT, # default
       size=kvadblib . ValueSize( startbit=0, length=32) ,
       scaling=kvadblib . ValueScaling( factor=1, offset=0) ,
       limits=kvadblib . ValueLimits(min=0, max=100) ,
       unit=’ metric ton ’ ,
       comment=’Measured load in system . ’ )


There are a lot of information that is specified when creating a signal, so let us quickly go through those options:

name A unique string identifying the signal. This name must be unique across all signals in the database.

type A signal can be specified as SIGNEDUNSIGNED, (DOUBLE4 ), or FLOAT. The signal may also be an enumerated type, and in that case we set the type as ENUM_SIGNED or ENUM_UNSIGNED in the Python wrapper.

byte_order The signal byte order can be either INTEL or MOTOROLA, defaults to INTEL.

mode The default mode for a signal is MUX_INDEPENDENT, which means that this signal is a normal signal.5 In a CAN message a signal can be defined as a multiplexor by setting mode to MUX_SIGNAL. This multiplexor now selects which multiplexed signal is transmitted in the same frame. The multiplexed signals should set mode to the (positive integer) multiplexed value the multiplexor should have for the multiplexed signal to be used. Only simple multiplexing is currently supported in kvadblib. For simple multiplexing only one multiplexor signal can be defined in a message, and for each multiplexed signal only one multiplexor value can be defined.

size The position of the signal’s first bit (aka as the startbit), and the length of the signal in number of bits.

scaling The scaling consists of a factor and an offset. A raw CAN value will be multiplied by the factor and then incremented with the offset to be converted to a physical value.

limits The minimum and maximum values of this signal’s physical value.

unit A string representation of the signal’s unit.

comment A string that can be used to document the signal.

Let us finish up the database by defining three more messages and signals.

message = db.new_message(name=’ECM_004’ ,
                         id=504,
                         dlc=8)

message . new_signal(name=’Fuel ’ ,
                     type=kvadblib . SignalType .FLOAT
                     size=kvadblib . ValueSize( startbit=0, length=32) ,
                     limits=kvadblib . ValueLimits(min=0, max=300) ,
                     unit=’ l /100 km’ ,
                     comment=’Current fuel consumption . ’ )

message = db.new_message(name=’ECM_003’ ,
                         id=503,
                         dlc=8)

message . new_signal(name=’EngineTemp ’ ,
                     type=kvadblib . SignalType .FLOAT,
                     size=kvadblib . ValueSize( startbit=0, length=32) ,
                     limits=kvadblib . ValueLimits(min=-60, max=200) ,
                     unit=’ Celsius ’ ,
                     comment=’System temperature consumption . ’ )

message = db.new_message(name=’ECM_001’ ,
                         id=501,
                         dlc=8)

message . new_signal(name=’EngineSpeed ’ ,
                     type=kvadblib . SignalType .UNSIGNED,
                     size=kvadblib . ValueSize( startbit=0, length=32) ,
                     limits=kvadblib . ValueLimits(min=0, max=6000) ,
                     unit=’rpm’ ,
                     comment=’Current engine speed . ’ )

The last step is to save our new database to a file and close it.

# write database f i l e
db. write_file ( ’db_histogram . dbc ’ )
db. close ()

Examining our database

Let us now take a look at the DBC database we just created. We start by just printing the contents from Python:

import textwrap
from canlib import kvadblib

with kvadblib .Dbc( filename=’db_histogram . dbc ’ ) as db:
    print (db)
    for message in db:
        print ( ’\n {} ’ . format(message) )
        for signal in message :
            print (textwrap . f i l l ( ’ {} ’ . format( signal ) , 80))

The textwrap module is used here to get a nice width of 80 characters on the printout:

Dbc db_histogram: flags:0, protocol:CAN, messages:4

 Message(name=’LIM_002’, id=402, flags=<MessageFlag.0: 0>, dlc=8, comment=’’)
  Signal(name=’Load’, type=<SignalType.FLOAT: 3>,
byte_order=<SignalByteOrder.INTEL: 0>, mode=-1, size=ValueSize(startbit=0,
length=32), scaling=ValueScaling(factor=1.0, offset=0.0),
limits=ValueLimits(min=0.0, max=100.0), unit=’metric ton’, comment=’Measured
load in system.’)

  Message(name=’ECM_004’, id=504, flags=<MessageFlag.0: 0>, dlc=8, comment=’’)
   Signal(name=’Fuel’, type=<SignalType.FLOAT: 3>,
byte_order=<SignalByteOrder.INTEL: 0>, mode=-1, size=ValueSize(startbit=0,
length=32), scaling=ValueScaling(factor=1.0, offset=0.0),
limits=ValueLimits(min=0.0, max=300.0), unit=’l/100 km’, comment=’Current fuel
consumption.’)

  Message(name=’ECM_003’, id=503, flags=<MessageFlag.0: 0>, dlc=8, comment=’’)
   Signal(name=’EngineTemp’, type=<SignalType.FLOAT: 3>,
byte_order=<SignalByteOrder.INTEL: 0>, mode=-1, size=ValueSize(startbit=0,
length=32), scaling=ValueScaling(factor=1.0, offset=0.0),
limits=ValueLimits(min=-60.0, max=200.0), unit=’Celsius’, comment=’System
temperature consumption.’)

  Message(name=’ECM_001’, id=501, flags=<MessageFlag.0: 0>, dlc=8, comment=’’)
   Signal(name=’EngineSpeed’, type=<SignalType.UNSIGNED: 2>,
byte_order=<SignalByteOrder.INTEL: 0>, mode=-1, size=ValueSize(startbit=0,
length=32), scaling=ValueScaling(factor=1.0, offset=0.0),
limits=ValueLimits(min=0.0, max=6000.0), unit=’rpm’, comment=’Current engine
speed.’)

Hopefully there were no surprises there, so let us finish this part of this blog series by also see how our database looks in the Kvaser Database Editor.

Figure 1: Looking at our newly created database in the Kvaser Database Editor.

In the middle panel of Kvaser Database Editor, we can see our four defined messages. In Figure 1, the message “LIM_002” is selected and the content of the message is shown below the message. In our case we have a single signal named “Load” with e.g. unit set to “metric ton”. In the right pane, a layout (with shadowed cells) of the current messsage’s data bits is shown. In Figure 1, we can see that the selected signal spans from bit 0 in the first byte through bit 7 in the third byte, this corresponds to the start position 0 and length 32 that was given.


Thus ends our first part which described how to create a database. In the next part we will take a look at how use the database while sending and receiving signals


Footnotes

1 The DBC database describes the properties of the CAN network, the nodes connected, and the CAN messages and signals.

2 https://www.kvaser.com/developer-blog/python-samples-now-bundled-package/

3 If you have been browsing around the t samples in the CANlib SDK, you might have come across this particular database before since it can be found in the folder Samples\tScript\Learn more\Misc\histogram.

4 The signal type DOUBLE is currently not implemented in kvadblib.

5 We will only cover normal (non-multiplexed) signals in this article.

Author Image

Magnus Carlsson

Magnus Carlsson is a Software Developer for Kvaser AB and has developed firmware and software for Kv...