Use Vehicle Network Toolbox with multiple CAN databases on a single CAN bus
17 次查看(过去 30 天)
显示 更早的评论
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.
2 个评论
Nishant Elkunchwar
2022-3-7
I second this question. The ability to add multiple dbc files to a channel is an essential functionality since the database files are usually defined per module.
Nishant Elkunchwar
2022-8-26
回答(1 个)
Daniel Bengtson
2024-7-17
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.
0 个评论
另请参阅
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!