Main Content

以编程方式构建 CAN 通信的 Simulink 模型

此示例说明如何以编程方式构建 Simulink® 模型,以使用 CAN DBC 文件来引入 CAN 或 CAN FD 通信。使用 Simulink 的 add_block (Simulink)set_param (Simulink) 函数,您可以添加并完整配置 Vehicle Network Toolbox™ 模块,以将网络通信添加到基本算法中。DBC 文件包含 CAN 报文和信号详细信息。首先需要以编程方式配置 CAN 和 CAN FD 的 Pack 和 Unpack 模块参数。这可以显著提高模型构造效率。

算法模型

示例模型 AlgorithmModel.slx 包含一个名为 Algorithm 的子系统模块。该模块表示在 Simulink 中开发的任何给定应用程序算法。出于演示目的,此子系统内部的 Gain (Simulink) 模块的值为 2。此子系统将 CAN 信号输入命名为“In1”。该输入值按增益值缩放。缩放值作为子系统的输出,命名为“Out1”。为了进行试验,可以更改增益值,并且可以用不同算法替换 Gain 模块。

CAN 数据库文件访问

您可以使用 canDatabase 函数访问 CAN DBC 文件的内容。通过此函数,可以获得关于网络节点、报文和信号的详细信息。

db = canDatabase("CANBus.dbc")
db = 
  Database with properties:

             Name: 'CANBus'
             Path: 'C:\Users\jpyle\Documents\MATLAB\Examples\vnt-ex60686316\CANBus.dbc'
            Nodes: {'ECU'}
         NodeInfo: [1×1 struct]
         Messages: {2×1 cell}
      MessageInfo: [2×1 struct]
       Attributes: {}
    AttributeInfo: [0×0 struct]
         UserData: []

示例 CAN DBC 文件中定义了节点“ECU”,如下所示。

node = nodeInfo(db,"ECU")
node = struct with fields:
             Name: 'ECU'
          Comment: ''
       Attributes: {}
    AttributeInfo: [0×0 struct]

该节点接收包含信号“InitialValue”的 CAN 报文“AlgInput”。信号“InitialValue”是算法的输入。

messageInfo(db,"AlgInput")
ans = struct with fields:
             Name: 'AlgInput'
     ProtocolMode: 'CAN'
          Comment: ''
               ID: 100
         Extended: 0
            J1939: []
           Length: 1
              DLC: 1
              BRS: 0
          Signals: {'InitialValue'}
       SignalInfo: [1×1 struct]
          TxNodes: {0×1 cell}
       Attributes: {}
    AttributeInfo: [0×0 struct]

该节点传输包含信号“ScaledValue”的 CAN 报文“AlgOutput”。信号“ScaledValue”是算法的输出。

messageInfo(db,"AlgOutput")
ans = struct with fields:
             Name: 'AlgOutput'
     ProtocolMode: 'CAN'
          Comment: ''
               ID: 200
         Extended: 0
            J1939: []
           Length: 2
              DLC: 2
              BRS: 0
          Signals: {'ScaledValue'}
       SignalInfo: [1×1 struct]
          TxNodes: {'ECU'}
       Attributes: {}
    AttributeInfo: [0×0 struct]

以编程方式构建模型

打开示例模型

打开要配置的示例模型。

open AlgorithmModel

添加和配置 CAN Configuration 模块

在模型中添加并放置一个 CAN Configuration 模块。

add_block("canlib/CAN Configuration","AlgorithmModel/CAN Configuration")
set_param("AlgorithmModel/CAN Configuration","position",[50,330,250,410])

设置“Device”参数,以使模型使用 MathWorks® 虚拟 CAN 设备。

set_param("AlgorithmModel/CAN Configuration","Device","MathWorks Virtual 1 (Channel 1)")

添加和配置 CAN Receive 模块

在模型中添加并放置一个 CAN Receive 模块。

add_block("canlib/CAN Receive","AlgorithmModel/CAN Receive")
set_param("AlgorithmModel/CAN Receive","position",[50,200,250,280])

添加并放置一个 Terminator (Simulink) 模块。这用于连接 CAN Receive 模块的函数端口。在此示例中,我们将执行简单的报文接收。一般情况下,将 CAN Receive 放在Function-Call Subsystem (Simulink)内是使用 CAN 模块建模的首选方法。

add_block("simulink/Sinks/Terminator","AlgorithmModel/Terminator")
set_param("AlgorithmModel/Terminator","position",[310,210,330,230])

设置“Device”参数,以使模型使用 MathWorks 虚拟 CAN 设备。

set_param("AlgorithmModel/CAN Receive","Device","MathWorks Virtual 1 (Channel 1)")

添加和配置 CAN Unpack 模块

在模型中添加并放置一个 CAN Unpack 模块。默认情况下,该模块处于“原始数据”模式。

add_block("canlib/CAN Unpack","AlgorithmModel/CAN Unpack")
set_param("AlgorithmModel/CAN Unpack","position",[350,220,600,300])

在单次函数调用中,在 CAN Unpack 模块中设置以下参数:

  • DataFormat

  • CANdbFile

  • MsgList

set_param("AlgorithmModel/CAN Unpack","DataFormat","CANdb specified signals","CANdbFile",db.Path,"MsgList","AlgInput")

如果已对模块设置“DataFormat”和“CANdbFile”参数,则可以通过只包括“MsgList”参数来更改所选报文。

添加和配置 CAN Pack 模块

在模型中添加并放置一个 CAN Pack 模块。

add_block("canlib/CAN Pack","AlgorithmModel/CAN Pack")
set_param("AlgorithmModel/CAN Pack","position",[1000,220,1250,300])

在单次函数调用中,在 CAN Pack 模块中设置以下参数:

  • DataFormat

  • CANdbFile

  • MsgList

set_param("AlgorithmModel/CAN Pack","DataFormat","CANdb specified signals","CANdbFile",db.Path,"MsgList","AlgOutput")

添加和配置 CAN Transmit 模块

在模型中添加并放置一个 CAN Transmit 模块。

add_block("canlib/CAN Transmit","AlgorithmModel/CAN Transmit")
set_param("AlgorithmModel/CAN Transmit","position",[1350,220,1550,300])

设置“Device”参数,以使模型使用 MathWorks 虚拟 CAN 设备。此外,使用默认时序启用周期性传输。

set_param("AlgorithmModel/CAN Transmit","Device","MathWorks Virtual 1 (Channel 1)")
set_param("AlgorithmModel/CAN Transmit", "EnablePeriodicTransmit", "on")

在模块之间建立连接

现在必须连接在模型中添加的 CAN 模块和算法模块。需要所有 CAN 模块的端口坐标。

canRxPort = get_param("AlgorithmModel/CAN Receive","PortConnectivity");
canUnpackPort = get_param("AlgorithmModel/CAN Unpack","PortConnectivity");
subSystemPort = get_param("AlgorithmModel/Subsystem","PortConnectivity");
canPackPort = get_param("AlgorithmModel/CAN Pack","PortConnectivity");
canTxPort = get_param("AlgorithmModel/CAN Transmit","PortConnectivity");
terminatorPort = get_param("AlgorithmModel/Terminator","PortConnectivity");

[canRxPortFunc,canRxPortMsg] = canRxPort.Position;
[canUnpackPortIn,canUnpackPortOut] = canUnpackPort.Position;
[subSystemPortIn,subSystemPortOut] = subSystemPort.Position;
[canPackPortIn,canPackPortOut] = canPackPort.Position;
canTxPortMsg = canTxPort.Position;
terminatorPortIn = terminatorPort.Position;

添加信号线,以适当的顺序连接所有模块。

add_line("AlgorithmModel",[canRxPortMsg ; canUnpackPortIn])
add_line("AlgorithmModel",[canUnpackPortOut ; subSystemPortIn])
add_line("AlgorithmModel",[subSystemPortOut ; canPackPortIn])
add_line("AlgorithmModel",[canPackPortOut ; canTxPortMsg])
add_line("AlgorithmModel",[canRxPortFunc ; terminatorPortIn])

完成的模型

这就是构建和配置后的模型外观。

测试构建的模型

在 MATLAB 中配置 CAN 通道以与算法模型通信

使用 MathWorks 虚拟 CAN 设备的通道 2 在 MATLAB® 中创建 CAN 通道。它将与模型中的 CAN 通道通信。此外,将 CAN 数据库连接到 MATLAB 通道,使其自动解码传入的 CAN 数据。

canCh = canChannel("MathWorks","Virtual 1",2);
canCh.Database = db;

对于从 MATLAB 到模型的传输,使用 CAN 数据库准备 CAN 报文作为算法的输入。

algInputMsg = canMessage(canCh.Database,"AlgInput");

运行算法模型

指定仿真时间并开始仿真

set_param("AlgorithmModel","StopTime","inf")
set_param("AlgorithmModel","SimulationCommand","start")

暂停,直到仿真完全启动。

while strcmp(get_param("AlgorithmModel","SimulationStatus"),"stopped")
end

运行 MATLAB 代码

启动 MATLAB CAN 通道。

start(canCh);

将具有不同信号数据的多个 CAN 报文作为模型的输入进行传输。

for value = 1:5
    algInputMsg.Signals.InitialValue = value*value;
    transmit(canCh,algInputMsg)
    pause(1)
end

从总线接收所有报文。请注意“AlgInput”和“AlgOutput”报文的实例、其时序和信号值。

msg = receive(canCh,Inf,"OutputFormat","timetable")
msg=10×8 timetable
        Time        ID     Extended        Name            Data        Length      Signals       Error    Remote
    ____________    ___    ________    _____________    ___________    ______    ____________    _____    ______

    0.009728 sec    100     false      {'AlgInput' }    {[      1]}      1       {1×1 struct}    false    false 
    0.15737 sec     200     false      {'AlgOutput'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    1.0121 sec      100     false      {'AlgInput' }    {[      4]}      1       {1×1 struct}    false    false 
    1.1574 sec      200     false      {'AlgOutput'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    2.0146 sec      100     false      {'AlgInput' }    {[      9]}      1       {1×1 struct}    false    false 
    2.1574 sec      200     false      {'AlgOutput'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    3.0177 sec      100     false      {'AlgInput' }    {[     16]}      1       {1×1 struct}    false    false 
    3.1574 sec      200     false      {'AlgOutput'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    4.0219 sec      100     false      {'AlgInput' }    {[     25]}      1       {1×1 struct}    false    false 
    4.1574 sec      200     false      {'AlgOutput'}    {1×2 uint8}      2       {1×1 struct}    false    false 

canSignalTimetable 函数提供了一种有效的方法,可以将 CAN 报文的信号值分离并针对每个报文组织成单个时间表。

signalTimeTable = canSignalTimetable(msg)
signalTimeTable = struct with fields:
     AlgInput: [5×1 timetable]
    AlgOutput: [5×1 timetable]

signalTimeTable.AlgInput
ans=5×1 timetable
        Time        InitialValue
    ____________    ____________

    0.009728 sec          1     
    1.0121 sec            4     
    2.0146 sec            9     
    3.0177 sec           16     
    4.0219 sec           25     

signalTimeTable.AlgOutput
ans=5×1 timetable
       Time        ScaledValue
    ___________    ___________

    0.15737 sec         2     
    1.1574 sec          8     
    2.1574 sec         18     
    3.1574 sec         32     
    4.1574 sec         50     

停止 CAN 通道。

stop(canCh)

停止算法模型

set_param("AlgorithmModel","SimulationCommand","stop")

绘制信号数据

绘制虚拟总线上出现的 CAN 报文的初始信号值和缩放信号值对时间戳的图。请注意由 MATLAB 传输的值的变化和由模型执行的数据缩放。

plot(signalTimeTable.AlgInput.Time,signalTimeTable.AlgInput.InitialValue,"Marker","square","MarkerIndices",1:5)
hold on
plot(signalTimeTable.AlgOutput.Time,signalTimeTable.AlgOutput.ScaledValue,"Marker","square","MarkerIndices",1:5)
hold off
xlabel("TimeStamp");
ylabel("CAN Signal Value");
legend("Initial Value","Scaled Value","Location","northeastoutside");
legend("boxoff");