Use Vehicle Network Toolbox with multiple CAN databases on a single CAN bus

17 views (last 30 days)
I'm using Vehicle Network Toolbox (VNT) to itneract with a CAN bus using database files (.dbc files). I've got it working with the code below.
chanA = canChannel('Kvaser', 'Leaf Light v2 1', 1);
chanA.Database = canDatabase('OperatorControl.dbc');
That works fine, but now I want to interact with messages that are defined in different databases, but are on the same CAN bus. What is the best way to do that? Should I define a new CAN channel? I could do that, but it seems like it would become cumbersome if there are a lot of extra channels to deal with.
Can I combine multiple CAN databases into a single one before adding it to the CAN channel? Can I add more than one database to the CAN channel? I haven't been able to find a way to do that.
Thank you.

Answers (1)

Daniel Bengtson
Daniel Bengtson on 17 Jul 2024
There is a way to allow for an arbitraty number of databases to be applied to the same channel, but it is either rather involved or requires editing a core VNT class definition. I have only tested it with Vector hardware and the matlab virtual bus so far, so I cannot garantee that it works with Kvaser or with all VNT functions. I have confirmed that it allows for multiple databases to populate message names and signal data when reading from a live bus.
You can make an array of databases that retains the 'Database' class by doing something along these lines.
dbcDir = dir('databases\*.dbc'); % import DBC used for all processing
% read database files into dbc array
for i = 1:length(dbcDir)
dbc(i) = canDatabase(strcat(dbcDir(i).folder,'\',dbcDir(i).name));
end
If you were to try take this array and set it as the database:
canch = canChannel('Vector','VN1610 1',2); % setup CAN channel
canch.Database = dbc; % set array of databases for channel
you will get an error like this:
Operands to the logical AND (&&) and OR (||) operators must be convertible to logical scalar values. Use the ANY or ALL functions to reduce operands to logical scalar values.
Error in can.Channel/set.Database (line 1315)
if isa(newValue, 'can.Database') && isvalid(newValue) && newValue.Usable
This is the function that breaks when trying to apply an array of databases to a CAN channel. It is lines 1307-1322 of can.Channel.
function set.Database(obj, newValue)
% Validate the channel before using its functionality.
assertValidity(obj);
% Validate the new value. The value must be either a valid
% can.Database type and a valid handle object or it must be
% empty. Setting the property to empty is used to clear the
% database from the channel.
if isa(newValue, 'can.Database') && isvalid(newValue) && newValue.Usable
obj.Database = newValue;
elseif isempty(newValue)
obj.Database = [];
else
error(message('vnt:Channel:InvalidDatabase'));
end
end
You can find the full path of this script by running:
which can.Channel
It breaks because of a simple dimension mismatch on line 1315 (the 'if'). The fix is also simple and is just to distill each of the three conditions down to a 1x1 logical value before &&ing them all together. The problem is that to implement the fix, we either have to edit a class definition in the VNT or (probably more safely) build a parallel set of functions that reference a new version of the Channel class definition. In this case that would likely require copying then modifying a substantial number of scripts within '\toolbox\vnt\vnt\+can'.
A modification such as shown below is all that is needed:
function set.Database(obj, newValue)
% Validate the channel before using its functionality.
assertValidity(obj);
% Validate the new value. The value must be either a valid
% can.Database type and a valid handle object or it must be
% empty. Setting the property to empty is used to clear the
% database from the channel.
% modified to use 'all' to essentially && each input along its own
% vector before &&ing the results for the real logical check
if isa(newValue, 'can.Database') && all(isvalid(newValue)) && all([newValue.Usable])
obj.Database = newValue;
elseif isempty(newValue)
obj.Database = [];
else
error(message('vnt:Channel:InvalidDatabase'));
end
end
Now we can set the channel.Database with an array of databases, set baud rate, start the channel, and start recording by:
dbcDir = dir('databases\*.dbc'); % paths for all DBCs to be used for processing
% read database files into dbc array
for i = 1:length(dbcDir)
dbc(i) = canDatabase(strcat(dbcDir(i).folder,'\',dbcDir(i).name));
end
canch = canChannel('Vector','VN1610 1',2); % setup CAN channel
canch.Database = dbc; % set array of databases for channel
tmp = get(canch); % init the channel so we can set baud rate
configBusSpeed(canch,250000); % set bus baud rate
start(canch); % start channel
msg = receive(canch,100000,OutputFormat="timetable"); % read next 100k messages on CAN bus
The 'Name' and 'Signals' fields in msg should have now populated referencing all databases provided by the array.

Products


Release

R2018b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!