Use Relative and Absolute Timestamps in CAN Communication
This example shows you how to use the InitialTimestamp
property of a CAN channel to work with relative and absolute timestamps for CAN messages. It uses MathWorks® virtual CAN channels connected in a loopback configuration. This example describes the workflow for a CAN network, but the concept demonstrated also applies to a CAN FD network.
Open the DBC File
Open the DBC file to access the database definitions.
db = canDatabase("VehicleInfo.dbc")
db = Database with properties: Name: 'VehicleInfo' Path: '/tmp/Bdoc24b_2679053_3933560/tpa5e3c087/vnt-ex13648766/VehicleInfo.dbc' UTF8_File: '/tmp/Bdoc24b_2679053_3933560/tpa5e3c087/vnt-ex13648766/VehicleInfo.dbc' Nodes: {} NodeInfo: [0x0 struct] Messages: {'WheelSpeeds'} MessageInfo: [1x1 struct] Attributes: {'BusType'} AttributeInfo: [1x1 struct] UserData: []
Create the CAN Channels
Create CAN channels on which you can transmit and receive messages.
txCh = canChannel("MathWorks", "Virtual 1", 1)
txCh = Channel with properties: Device Information DeviceVendor: 'MathWorks' Device: 'Virtual 1' DeviceChannelIndex: 1 DeviceSerialNumber: 0 ProtocolMode: 'CAN' Status Information Running: 0 MessagesAvailable: 0 MessagesReceived: 0 MessagesTransmitted: 0 InitializationAccess: 1 InitialTimestamp: [0x0 datetime] FilterHistory: 'Standard ID Filter: Allow All | Extended ID Filter: Allow All' Channel Information BusStatus: 'N/A' SilentMode: 0 TransceiverName: 'N/A' TransceiverState: 'N/A' ReceiveErrorCount: 0 TransmitErrorCount: 0 BusSpeed: 500000 SJW: [] TSEG1: [] TSEG2: [] NumOfSamples: [] Other Information Database: [] UserData: []
rxCh = canChannel("MathWorks", "Virtual 1", 2)
rxCh = Channel with properties: Device Information DeviceVendor: 'MathWorks' Device: 'Virtual 1' DeviceChannelIndex: 2 DeviceSerialNumber: 0 ProtocolMode: 'CAN' Status Information Running: 0 MessagesAvailable: 0 MessagesReceived: 0 MessagesTransmitted: 0 InitializationAccess: 1 InitialTimestamp: [0x0 datetime] FilterHistory: 'Standard ID Filter: Allow All | Extended ID Filter: Allow All' Channel Information BusStatus: 'N/A' SilentMode: 0 TransceiverName: 'N/A' TransceiverState: 'N/A' ReceiveErrorCount: 0 TransmitErrorCount: 0 BusSpeed: 500000 SJW: [] TSEG1: [] TSEG2: [] NumOfSamples: [] Other Information Database: [] UserData: []
Attach the database directly to the receiving channel to apply database definitions to incoming messages automatically.
rxCh.Database = db;
Create the CAN Message
Create a new CAN message by specifying the database and the message name WheelSpeeds
to have the database definition applied.
msg = canMessage(db, "WheelSpeeds")
msg = Message with properties: Message Identification ProtocolMode: 'CAN' ID: 1200 Extended: 0 Name: 'WheelSpeeds' Data Details Timestamp: 0 Data: [0 0 0 0 0 0 0 0] Signals: [1x1 struct] Length: 8 Protocol Flags Error: 0 Remote: 0 Other Information Database: [1x1 can.Database] UserData: []
Start the CAN Channels
Start the channels to begin using them for transmission and reception.
start(rxCh) start(txCh)
Transmit CAN Messages
The transmit
function sends messages onto the network. Use pause
to add delays between the transmit operations. Update the LF_WSpeed
signal value before each transmission.
msg.Signals.LF_WSpeed = 10; transmit(txCh, msg) pause(1); msg.Signals.LF_WSpeed = 20; transmit(txCh, msg) pause(2); msg.Signals.LF_WSpeed = 30; transmit(txCh, msg) pause(3); msg.Signals.LF_WSpeed = 40; transmit(txCh, msg) pause(1); msg.Signals.LF_WSpeed = 50; transmit(txCh, msg)
Receive the CAN Messages
The receive
function receives CAN messages that occurred on the network.
stop(rxCh) stop(txCh) msgRx = receive(rxCh, Inf, "OutputFormat", "timetable")
msgRx=5×8 timetable
Time ID Extended Name Data Length Signals Error Remote
____________ ____ ________ _______________ ______________________ ______ ____________ _____ ______
0.018695 sec 1200 false {'WheelSpeeds'} {[42 248 0 0 0 0 0 0]} 8 {1x1 struct} false false
1.0385 sec 1200 false {'WheelSpeeds'} {[46 224 0 0 0 0 0 0]} 8 {1x1 struct} false false
3.0559 sec 1200 false {'WheelSpeeds'} {[50 200 0 0 0 0 0 0]} 8 {1x1 struct} false false
6.0726 sec 1200 false {'WheelSpeeds'} {[54 176 0 0 0 0 0 0]} 8 {1x1 struct} false false
7.0874 sec 1200 false {'WheelSpeeds'} {[58 152 0 0 0 0 0 0]} 8 {1x1 struct} false false
Inspect Signal Data
Use canSignalTimetable
to repackage signal data from the received messages into a signal timetable. Note that timestamp values represent time elapsed from the start of the CAN channel.
signalTimetable = canSignalTimetable(msgRx)
signalTimetable=5×4 timetable
Time LR_WSpeed RR_WSpeed RF_WSpeed LF_WSpeed
____________ _________ _________ _________ _________
0.018695 sec -100 -100 -100 10
1.0385 sec -100 -100 -100 20
3.0559 sec -100 -100 -100 30
6.0726 sec -100 -100 -100 40
7.0874 sec -100 -100 -100 50
plot(signalTimetable.Time, signalTimetable.LF_WSpeed, "x") title("Signal Data with Relative Time", "FontWeight", "bold") xlabel("Relative Timestamp") ylabel("Signal Value") ylim([0 60])
Inspect InitialTimestamp
Property
View the InitialTimestamp
property of the receiving CAN channel. It is a datetime
value that represents the absolute time of when the channel is started.
rxCh.InitialTimestamp
ans = datetime
20-Jul-2024 13:58:25
Analyze Data with Absolute Timestamps
Combine the relative timestamp of each message and the InitialTimestamp
property to obtain the absolute timestamp of each message. Set the absolute timestamps back into the message timetable as the time vector.
msgRx.Time = msgRx.Time + rxCh.InitialTimestamp
msgRx=5×8 timetable
Time ID Extended Name Data Length Signals Error Remote
____________________ ____ ________ _______________ ______________________ ______ ____________ _____ ______
20-Jul-2024 13:58:25 1200 false {'WheelSpeeds'} {[42 248 0 0 0 0 0 0]} 8 {1x1 struct} false false
20-Jul-2024 13:58:26 1200 false {'WheelSpeeds'} {[46 224 0 0 0 0 0 0]} 8 {1x1 struct} false false
20-Jul-2024 13:58:28 1200 false {'WheelSpeeds'} {[50 200 0 0 0 0 0 0]} 8 {1x1 struct} false false
20-Jul-2024 13:58:31 1200 false {'WheelSpeeds'} {[54 176 0 0 0 0 0 0]} 8 {1x1 struct} false false
20-Jul-2024 13:58:32 1200 false {'WheelSpeeds'} {[58 152 0 0 0 0 0 0]} 8 {1x1 struct} false false
The signal timetable created from the updated message timetable now also has absolute timestamps.
signalTimetable = canSignalTimetable(msgRx)
signalTimetable=5×4 timetable
Time LR_WSpeed RR_WSpeed RF_WSpeed LF_WSpeed
____________________ _________ _________ _________ _________
20-Jul-2024 13:58:25 -100 -100 -100 10
20-Jul-2024 13:58:26 -100 -100 -100 20
20-Jul-2024 13:58:28 -100 -100 -100 30
20-Jul-2024 13:58:31 -100 -100 -100 40
20-Jul-2024 13:58:32 -100 -100 -100 50
figure plot(signalTimetable.Time, signalTimetable.LF_WSpeed, "x") title("Signal Data with Absolute Time", "FontWeight", "bold") xlabel("Absolute Timestamp") ylabel("Signal Value") ylim([0 60])
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