Main Content

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_2725827_3770987/tpf6b9d6b0/vnt-ex13648766/VehicleInfo.dbc'
        UTF8_File: '/tmp/Bdoc24b_2725827_3770987/tpf6b9d6b0/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.067694 sec    1200     false      {'WheelSpeeds'}    {[42 248 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    1.0891 sec      1200     false      {'WheelSpeeds'}    {[46 224 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    3.1005 sec      1200     false      {'WheelSpeeds'}    {[50 200 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    6.109 sec       1200     false      {'WheelSpeeds'}    {[54 176 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    7.1251 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.067694 sec      -100         -100         -100          10    
    1.0891 sec        -100         -100         -100          20    
    3.1005 sec        -100         -100         -100          30    
    6.109 sec         -100         -100         -100          40    
    7.1251 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])

Figure contains an axes object. The axes object with title Signal Data with Relative Time, xlabel Relative Timestamp, ylabel Signal Value contains a line object which displays its values using only markers.

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
   05-Sep-2024 23:17:47

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
    ____________________    ____    ________    _______________    ______________________    ______    ____________    _____    ______

    05-Sep-2024 23:17:47    1200     false      {'WheelSpeeds'}    {[42 248 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    05-Sep-2024 23:17:48    1200     false      {'WheelSpeeds'}    {[46 224 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    05-Sep-2024 23:17:50    1200     false      {'WheelSpeeds'}    {[50 200 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    05-Sep-2024 23:17:53    1200     false      {'WheelSpeeds'}    {[54 176 0 0 0 0 0 0]}      8       {1x1 struct}    false    false 
    05-Sep-2024 23:17:54    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
    ____________________    _________    _________    _________    _________

    05-Sep-2024 23:17:47      -100         -100         -100          10    
    05-Sep-2024 23:17:48      -100         -100         -100          20    
    05-Sep-2024 23:17:50      -100         -100         -100          30    
    05-Sep-2024 23:17:53      -100         -100         -100          40    
    05-Sep-2024 23:17:54      -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])

Figure contains an axes object. The axes object with title Signal Data with Absolute Time, xlabel Absolute Timestamp, ylabel Signal Value contains a line object which displays its values using only markers.

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