Periodic CAN Communication in MATLAB
This example shows you how to how to configure CAN channels and messages for transmit messages periodically. It uses MathWorks® virtual CAN channels connected in a loopback configuration.
As this example is based on sending and receiving CAN messages on a virtual network, running CAN Explorer in conjunction may provide a more complete understanding of what the code is doing. To run CAN Explorer, open and configure it to use the same interface as the receiving channel of the example. Make sure to start CAN Explorer before beginning to run the example in order to see all of the messages as they occur.
This example describes the workflow for a CAN network, but the concept demonstrated also applies to a CAN FD network.
Create the CAN Channels
Create CAN channels for message transmission and reception.
txCh = canChannel("MathWorks", "Virtual 1", 1); rxCh = canChannel("MathWorks", "Virtual 1", 2);
Open the DBC file that contains message and signal definitions, and attach it to both CAN channels.
db = canDatabase("CANDatabasePeriodic.dbc");
txCh.Database = db;
rxCh.Database = db;
Create the CAN Messages
Create CAN messages EngineMsg
and TransmissionMsg
using the database information.
msgFast = canMessage(db, "EngineMsg")
msgFast = Message with properties: Message Identification ProtocolMode: 'CAN' ID: 100 Extended: 0 Name: 'EngineMsg' Data Details Timestamp: 0 Data: [0 0 0 0 0 0 0 0] Signals: [1×1 struct] Length: 8 Protocol Flags Error: 0 Remote: 0 Other Information Database: [1×1 can.Database] UserData: []
msgSlow = canMessage(db, "TransmissionMsg")
msgSlow = Message with properties: Message Identification ProtocolMode: 'CAN' ID: 200 Extended: 0 Name: 'TransmissionMsg' Data Details Timestamp: 0 Data: [0 0 0 0 0 0 0 0] Signals: [1×1 struct] Length: 8 Protocol Flags Error: 0 Remote: 0 Other Information Database: [1×1 can.Database] UserData: []
Configure Messages for Periodic Transmission
To enable a message for periodic transmission, use the transmitPeriodic
command specifying the transmitting channel, the message to register on the channel, a state value, and the periodic rate.
transmitPeriodic(txCh, msgFast, "On", 0.100); transmitPeriodic(txCh, msgSlow, "On", 0.500);
Start the Periodic Transmission
Start the receiving channel.
start(rxCh);
Start the transmitting channel with periodic transmission configured in the previous step. Period transmission begins immediately. Allow the channels to run for two seconds.
start(txCh); pause(2);
Update Transmitted Data
To update the live messages or signal data transmitted onto the CAN bus, write new values directly to the VehicleSpeed
signal in message EngineMsg
.
msgFast.Signals.VehicleSpeed = 60; pause(1); msgFast.Signals.VehicleSpeed = 65; pause(1); msgFast.Signals.VehicleSpeed = 70; pause(1);
Alternatively, you can write new values to the Data
property of the created messages.
Receive the Messages
Stop the CAN channels and receive all periodically transmitted messages for analysis.
stop(txCh); stop(rxCh); msgRx = receive(rxCh, Inf, "OutputFormat", "timetable");
View the first few rows of the received messages using the head
function.
head(msgRx)
Time ID Extended Name Data Length Signals Error Remote ____________ ___ ________ ___________________ ___________________ ______ ____________ _____ ______ 0.031922 sec 100 false {'EngineMsg' } {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.031924 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.13752 sec 100 false {'EngineMsg' } {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.24011 sec 100 false {'EngineMsg' } {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.35028 sec 100 false {'EngineMsg' } {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.45648 sec 100 false {'EngineMsg' } {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.53209 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.56215 sec 100 false {'EngineMsg' } {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false
Analyze the Behavior of Periodic Transmission
Analyze the distribution of messages by plotting the identifiers of each received message against their timestamps. Note the difference between how often the two messages appear according to the configured periodic rates.
plot(msgRx.Time, msgRx.ID, "x") ylim([0 400]) title("Message Distribution", "FontWeight", "bold") xlabel("Timestamp") ylabel("CAN Identifier")
For further analysis, separate the two messages into individual timetables.
msgRxFast = msgRx(strcmpi("EngineMsg", msgRx.Name), :);
head(msgRxFast)
Time ID Extended Name Data Length Signals Error Remote ____________ ___ ________ _____________ ___________________ ______ ____________ _____ ______ 0.031922 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.13752 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.24011 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.35028 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.45648 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.56215 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.66495 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.77479 sec 100 false {'EngineMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false
msgRxSlow = msgRx(strcmpi("TransmissionMsg", msgRx.Name), :);
head(msgRxSlow)
Time ID Extended Name Data Length Signals Error Remote ____________ ___ ________ ___________________ ___________________ ______ ____________ _____ ______ 0.031924 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 0.53209 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 1.0317 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 1.5323 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 2.0437 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 2.5418 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 3.0423 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false 3.5422 sec 200 false {'TransmissionMsg'} {[0 0 0 0 0 0 0 0]} 8 {1×1 struct} false false
Analyze the timestamps of each set of messages to see how closely the average of the differences corresponds to the configured periodic rates.
avgPeriodFast = mean(diff(msgRxFast.Time))
avgPeriodFast = duration
0.10604 sec
avgPeriodSlow = mean(diff(msgRxSlow.Time))
avgPeriodSlow = duration
0.50141 sec
Use canSignalTimetable
to repackage signal data from message EngineMsg
into a signal timetable.
signalTimetable = canSignalTimetable(msgRx, "EngineMsg");
head(signalTimetable)
Time VehicleSpeed EngineRPM ____________ ____________ _________ 0.031922 sec 0 250 0.13752 sec 0 250 0.24011 sec 0 250 0.35028 sec 0 250 0.45648 sec 0 250 0.56215 sec 0 250 0.66495 sec 0 250 0.77479 sec 0 250
Plot the received values of signal VehicleSpeed
over time and note how it reflects the three updates in message data.
plot(signalTimetable.Time, signalTimetable.VehicleSpeed) title("Vehicle Speed from EngineMsg", "FontWeight", "bold") xlabel("Timestamp") ylabel("Vehicle Speed") ylim([-5 75])
View Messages Configured for Periodic Transmission
To see messages configured on the transmitting channel for automatic transmission, use the transmitConfiguration
command.
transmitConfiguration(txCh)
Periodic Messages ID Extended Name Data Rate (seconds) --- -------- --------------- ----------------- -------------- 100 false EngineMsg 0 0 0 0 70 0 0 0 0.100000 200 false TransmissionMsg 0 0 0 0 0 0 0 0 0.500000 Event Messages None
Close the Channels and DBC File
Close access to the channels and the DBC file by clearing their variables from the workspace.
clear rxCh txCh clear db