Разработка приложения App Designer для модели Simulink с помощью CAN

В этом примере показано, как создать тестовый пользовательский интерфейс приложения (UI) и подключить его к модели Simulink с помощью виртуальных каналов CAN. Тестовое приложение UI сконструировано с помощью MATLAB App Designer™ вместе с несколькими функциями Vehicle Network Toolbox™ (VNT), чтобы обеспечить виртуальный интерфейс шины CAN для модели Simulink приложения автомобильного круиз-контроля. Пользовательский интерфейс тестового приложения позволяет пользователю предоставлять входной стимул модели алгоритма управления круиз-контроля, наблюдать результаты, отправленные из модели, регистрировать сообщения CAN для захвата тестовых стимулов и воспроизводить записанные сообщения CAN для отладки и исправления проблем с моделью алгоритма. В примере показаны ключевые функции Vehicle Network Toolbox и блоки, используемые для реализации связи CAN в следующих областях:

  • Пользовательский интерфейс тестового приложения, поддерживающий коммуникацию с моделью алгоритма Simulink для проверки через CAN

  • Пользовательский интерфейс тестового приложения, поддерживающий логгирование и воспроизведение данных CAN

  • Модель алгоритма Simulink

Добавление виртуальной канальной связи CAN к пользовательскому интерфейсу

В этом разделе мы описываем ключевые функции Vehicle Network Toolbox, используемые для добавления интерфейса канала CAN к модели тестирования алгоритма круиз-контроля Simulink. Это охватывает следующие темы:

  • Получение списка доступных каналов CAN

  • Форматирование информации о канале для создания канала

  • Создание канала в пользовательском интерфейсе

  • Сконфигурируйте UI для передачи и приема сообщений CAN

  • Запуск и остановка канала

  • Извлечение выбранных сообщений

Откройте App Designer

Откройте тестовое приложение UI в App Designer. С тестовым приложением UI, открытым в App Designer, вы можете чередовать представления «Design» и «Code», чтобы следовать вместе, когда вы исследуете элементы управления и соответствующий код MATLAB для связи с моделью алгоритма Simulink Cruise Control по виртуальным каналам CAN. Используйте следующую команду, чтобы открыть пример UI: appdesigner('CruiseControlTestUI.mlapp').

Список доступных каналов CAN

Сначала реализуйте механизм для поиска и представления списка доступных каналов CAN для выбора пользователем. Для этого мы добавили элемент меню «Channel Configuration» в левом верхнем углу пользовательского интерфейса тестового приложения. Он имеет подменю «Select CAN Channel».

Когда пользователь нажимает на подменю «Select CAN Channel», функция helper getAvailableCANChannelInfo(app) вызывается посредством коллбэка подменю. getAvailableCANChannelInfo() использует функцию Vehicle Network Toolbox для обнаружения доступных каналов CAN, как показано на фрагменте кода ниже:

function getAvailableCANChannelInfo(app)
    % Get a table containing all available CAN channels and devices.
    app.canChannelInfo = canChannelList;
    
    % Format CAN channel information for display on the UI.
    app.availableCANChannelsForDisplay = formatCANChannelEntryForDisplay(app);
    
    % Save the number of available constructors.
    app.numConstructors = numel(app.canChannelInfo.Vendor);
end

Запустите canChannelList, чтобы увидеть, как хранится доступная информация о канале CAN.

canChannels = canChannelList
canChannels=12×6 table
      Vendor         Device       Channel    DeviceModel    ProtocolMode     SerialNumber
    ___________    ___________    _______    ___________    _____________    ____________

    "MathWorks"    "Virtual 1"       1        "Virtual"     "CAN, CAN FD"      "0"       
    "MathWorks"    "Virtual 1"       2        "Virtual"     "CAN, CAN FD"      "0"       
    "Vector"       "VN1610 1"        1        "VN1610"      "CAN, CAN FD"      "46457"   
    "Vector"       "VN1610 1"        2        "VN1610"      "CAN, CAN FD"      "46457"   
    "Vector"       "VN1610 3"        1        "VN1610"      "CAN, CAN FD"      "46456"   
    "Vector"       "VN1610 3"        2        "VN1610"      "CAN, CAN FD"      "46456"   
    "Vector"       "VN1610 2"        1        "VN1610"      "CAN, CAN FD"      "48599"   
    "Vector"       "VN1610 2"        2        "VN1610"      "CAN, CAN FD"      "48599"   
    "Vector"       "Virtual 1"       1        "Virtual"     "CAN, CAN FD"      "0"       
    "Vector"       "Virtual 1"       2        "Virtual"     "CAN, CAN FD"      "0"       
    "Kvaser"       "Virtual 1"       1        "Virtual"     "CAN, CAN FD"      "0"       
    "Kvaser"       "Virtual 1"       2        "Virtual"     "CAN, CAN FD"      "0"       

Список каналов, возвращенных из canChannelList, хранится в свойстве UI app.canChannelInfo а затем отображается пользователю в списке «Канал CAN Selection», как показано на экране, снятом выше.

Форматируйте список каналов для строения каналов

Пользователь выбирает канал CAN из списка «CAN Channel Selection». listdlg возвращает индекс, соответствующий выбору пользователя. Этот индекс передается в вспомогательную функцию formatCANChannelConstructor.

function canChannelConstructor = formatCANChannelConstructor(app, index)
    canChannelConstructor = "canChannel(" + "'" + app.canChannelInfo.Vendor(index) + "'" + ", " + "'" + app.canChannelInfo.Device(index) + "'" + ", " + app.canChannelInfo.Channel(index) + ")";
end

Как показано на фрагменте кода выше, formatCANChannelConstructor использует строки, хранящиеся в таблице каналов CAN, app.canChannelInfo, чтобы собрать строку конструктора объектов канала, соответствующую каналу, выбранному пользователем из диалогового окна списка селекторов каналов. Чтобы увидеть пример строки конструктора канала CAN, выполните код, показанный ниже.

index = 1;
canChannelConstructor = "canChannel(" + "'" + canChannels.Vendor(index) + "'" + ", " + "'" + canChannels.Device(index) + "'" + ", " + canChannels.Channel(index) + ")"
canChannelConstructor = 
"canChannel('MathWorks', 'Virtual 1', 1)"

Строка конструктора канала CAN сохранена в свойстве UI приложения app.canChannelConstructorSelected и будет использоваться позже, чтобы создать выбранный объект канала CAN в пользовательском интерфейсе приложения, а также обновить блоки Vehicle Network Toolbox Simulink, которые реализуют интерфейс канала CAN в модели алгоритма Simulink Cruise Control.

Создайте канал CAN в пользовательском интерфейсе

Когда пользовательский интерфейс впервые открыт и инициализирован, форматированная строка конструктора канала CAN, сохраненная в app.canChannelConstructorSelected, используется вспомогательной функцией setupCANChannel чтобы создать образец объекта канала CAN, подключите файл базы данных строения сети (.DBC) и установите скорость шины, как показано на фрагменте кода ниже. Получившийся объект канала сохранен в свойстве UI app.canChannelObject.

function setupCANChannel(app)
    % Open CAN database file.
    db = canDatabase('CruiseControl.dbc');
    
    % Create a CAN channel for sending and receiving messages.
    app.canChannelObj = eval(app.canChannelConstructorSelected);
    
    % Attach CAN database to channel for received message decoding.
    app.canChannelObj.Database = db;
    
    % Set the baud rate (can only do this if the UI has channel initialization access).
    if app.canChannelObj.InitializationAccess
        configBusSpeed(app.canChannelObj, 500000);
    end
end 

To see an example CAN database object, execute the following:

db = canDatabase('CruiseControl.dbc')
db = 
  Database with properties:

             Name: 'CruiseControl'
             Path: '\\fs-01-mi\shome$\rollinb\Documents\MATLAB\Examples\vnt-ex00964061\CruiseControl.dbc'
            Nodes: {2×1 cell}
         NodeInfo: [2×1 struct]
         Messages: {2×1 cell}
      MessageInfo: [2×1 struct]
       Attributes: {'BusType'}
    AttributeInfo: [1×1 struct]
         UserData: []

To see an example CAN channel object, execute the following:

% Instantiate the CAN channel object using the channel constructor string.
canChannelObj = eval(canChannelConstructor);

% Attach the CAN database to the channel object.
canChannelObj.Database = db
canChannelObj = 
  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: [0×0 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: [1×1 can.Database]
                UserData: []

setupCANChannel использует следующие функции Vehicle Network Toolbox:

  • canChannel для создания экземпляров объекта канала с помощью команды eval и строки конструктора канала CAN, сохраненной в свойстве UI приложения app.canChannelConstructorSelected. Результирующий объект канала сохранен в свойстве UI приложения app.canChannelObj.

  • canDatabase для создания объекта базы данных CAN (.DBC), представляющего файл .DBC. Этот объект хранится в свойстве «Database» объекта канала.

Setup для передачи сообщений CAN

После настройки выбранного объекта канала CAN и хранения его в свойстве UI app.canChannelObj, следующим шагом является вызов вспомогательной функции setupCANTransmitMessages, показан на фрагменте кода ниже. setupCANTransmitMessages defines сообщение CAN для передачи от UI, заполняет полезную нагрузку сообщения сигналами, присваивает каждому сигналу значение и помещает сообщение в очередь для периодической передачи после запуска канала CAN.

function setupCANTransmitMessages(app)
    % Create a CAN message container.
    app.cruiseControlCmdMessage = canMessage(app.canChannelObj.Database, 'CruiseCtrlCmd');
    
    % Fill the message container with signals and assign values to each signal.
    app.cruiseControlCmdMessage.Signals.S01_CruiseOnOff = logical2Numeric(app, app.cruisePowerCheckBox.Value);
    app.cruiseControlCmdMessage.Signals.S02_Brake =  logical2Numeric(app, app.brakeOnOffCheckBox.Value);
    app.cruiseControlCmdMessage.Signals.S03_VehicleSpeed =  app.vehicleSpeedSlider.Value;
    app.cruiseControlCmdMessage.Signals.S04_CoastSetSw =  logical2Numeric(app, app.cruiseCoastSetCheckBox.Value);
    app.cruiseControlCmdMessage.Signals.S05_AccelResSw =  logical2Numeric(app, app.cruiseAccelResumeCheckBox.Value);
    
    % Set up periodic transmission of this CAN message.  Actual transmission starts/stops with CAN channel start/stop.
    transmitPeriodic(app.canChannelObj, app.cruiseControlCmdMessage, 'On', 0.1);
end

To see what the CAN message object looks like, execute the following:

cruiseControlCmdMessage = canMessage(canChannelObj.Database, 'CruiseCtrlCmd')
cruiseControlCmdMessage = 
  Message with properties:

   Message Identification
    ProtocolMode: 'CAN'
              ID: 256
        Extended: 0
            Name: 'CruiseCtrlCmd'

   Data Details
       Timestamp: 0
            Data: [0 0]
         Signals: [1×1 struct]
          Length: 2

   Protocol Flags
           Error: 0
          Remote: 0

   Other Information
        Database: [1×1 can.Database]
        UserData: []

cruiseControlCmdMessage.Signals
ans = struct with fields:
    S03_VehicleSpeed: 0
      S05_AccelResSw: 0
      S04_CoastSetSw: 0
           S02_Brake: 0
     S01_CruiseOnOff: 0

setupCANTransmitMessages использует следующие функции Vehicle Network Toolbox:

  • canMessage для создания сообщения CAN, заданного в объекте базы данных CAN.

  • transmitPeriodic для постановки в очередь сообщения, хранящегося в свойстве UI app.cruiseControlCmdMessage, для периодической передачи по каналу, заданному объектом канала, хранящимся в свойстве UI app.canChannelObj, со скоростью, заданной последним аргументом, в этом случае каждые 0,1 секунды.

Setup для получения сообщений CAN

UI должен получать сообщения CAN на периодическом базисный, чтобы обновить графики с обратной связью от Алгоритма управления Cruise в рамках модели Simulink. Чтобы добиться этого, мы сначала создадим объект-таймер MATLAB, как показано на фрагменте кода ниже.

% create a timer to receive CAN msgs
app.receiveCANmsgsTimer = timer('Period', 0.5,...
    'ExecutionMode', 'fixedSpacing', ...
    'TimerFcn', @(~,~)receiveCANmsgsTimerCallback(app));

Этот объект-таймер вызовет функцию обратного вызова таймера receiveCANmsgsTimerCallback каждые 0,5 секунды. receiveCANmsgsTimerCallback, показанный в фрагменте кода ниже, извлекает все сообщения CAN из шины, использует функцию helper getCruiseCtrlFBCANmessage чтобы извлечь сообщения CAN, отправленные обратно из модели алгоритма управления круиз-контроля, и обновляет графики UI с помощью извлеченных данных сообщения CAN.

% receiveCANmsgsTimerCallback Timer callback function for GUI updating
function receiveCANmsgsTimerCallback(app)
    try
        % Receive available CAN messages.
        msg = receive(app.canChannelObj, Inf, 'OutputFormat', 'timetable');
        
        % Update Cruise Control Feedback CAN message data.
        newFbData = getCruiseCtrlFBCANmessage(app, msg);
        
        if ~newFbData
            return;
        end
        
        % Update target speed and engaged plots with latest data from CAN bus.
        updatePlots(app);
    catch err
        disp(err.message)
    end
end

Чтобы увидеть сообщения, возвращенные из receive Как выглядит команда, запустите следующий код:

% Queue periodic transmission of a CAN message to generate some message data once the channel
% starts.
transmitPeriodic(canChannelObj, cruiseControlCmdMessage, 'On', 0.1);

% Start the channel.
start(canChannelObj);

% Wait 1 second to allow time for some messages to be generated on the bus.
pause(1);

% Retrieve all messages from the bus and output the results as a timetable.
msg = receive(canChannelObj, Inf, 'OutputFormat','timetable')
msg=31×8 timetable
        Time         ID     Extended          Name              Data        Length      Signals       Error    Remote
    _____________    ___    ________    _________________    ___________    ______    ____________    _____    ______

    0.0066113 sec    256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.059438 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.16047 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.26045 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.36045 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.46046 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.56046 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.66046 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.75945 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.86044 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.95945 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    1.0594 sec       256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    1.1594 sec       256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    1.2594 sec       256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    1.3595 sec       256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    1.4605 sec       256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
      ⋮

% Stop the channel.
stop(canChannelObj)

receiveCANmsgsTimerCallback использует следующие функции Vehicle Network Toolbox:

  • получите для извлечения сообщений CAN из шины CAN. В этом случае функция сконфигурирована для извлечения всех сообщений с момента предыдущего вызова и вывода результатов в виде расписания MATLAB.

Извлечение выбранных сообщений CAN

Функция помощника getCruiseCtrlFBCANmessage отфильтровывает сообщения «Cruise Ctrl FB» из всех извлеченных сообщений CAN, извлекает сигналы tspeed Fb и engled Fb из этих сообщений и конкатенирует их с объектами timeseries MATLAB для сигналов tspeed Fb и engled Fb. Эти объекты timeseries хранятся в свойствах UI app.tspeedFb и app.engagedFb, соответственно. Сохраненные сигналы timeseries используются, чтобы обновить графики для каждого сигнала на пользовательском интерфейсе. Обратите внимание на использование seconds способ преобразования временных данных, сохраненных в timetable, из массива длительности в эквивалентный числовой массив в единицах секунды в объектах timeseries для каждого сигнала.

function newFbData = getCruiseCtrlFBCANmessage(app, msg)
    % Exit if no messages were received as there is nothing to update.
    if isempty(msg)
        newFbData = false;
        return;
    end
    
    % Extract signals from all CruiseCtrlFB messages.
    cruiseCtrlFBSignals = canSignalTimetable(msg, "CruiseCtrlFB");
    
    % if no messages then just return as there is nothing to do
    if isempty(cruiseCtrlFBSignals)
        newFbData = false;
        return;
    end
    
    if ~isempty(cruiseCtrlFBSignals)
        % Received new Cruise Control Feedback messages, so create time series from CAN signal data
        % save the Target Speed feedback signal.
        if isempty(app.tspeedFb) % cCeck if target speed feedback property has been initialized.
            app.tspeedFb = cell(2,1);
            
            % It appears Simulink.SimulationData.Dataset class is not
            % compatible with MATLAB Compiler, so change the way we store data
            % from a Dataset format to cell array.
            
            % Save target speed actual data.
            app.tspeedFb = timeseries(cruiseCtrlFBSignals.F02_TargetSpeed, seconds(cruiseCtrlFBSignals.Time),...
                'Name','CruiseControlTargetSpeed');
        else  % Add to existing data.
            % Save target speed actual data.
            app.tspeedFb = timeseries([app.tspeedFb.Data; cruiseCtrlFBSignals.F02_TargetSpeed], ...
                [app.tspeedFb.Time; seconds(cruiseCtrlFBSignals.Time)],'Name','CruiseControlTargetSpeed');
        end
        
        % Save the Cruise Control Engaged actual signal.
        % Check if Cruise engaged property has been initialized.
        if isempty(app.engagedFb)    
            app.engagedFb = cell(2,1);

            % It appears Simulink.SimulationData.Dataset class is not
            % compatible with MATLAB Compiler, so change the way we store data
            % from a Dataset format to cell array.
            
            % Save cruise engaged command data.
            app.engagedFb = timeseries(cruiseCtrlFBSignals.F01_Engaged,seconds(cruiseCtrlFBSignals.Time),...
                'Name','CruiseControlEngaged');
        else  % Add to existing logsout.
            % Save cruise engaged command data.
            app.engagedFb = timeseries([app.engagedFb.Data; cruiseCtrlFBSignals.F01_Engaged], ...
                [app.engagedFb.Time; seconds(cruiseCtrlFBSignals.Time)],'Name','CruiseControlEngaged');
        end
        
        newFbData = true;
    end
end

Функция помощника getCruiseCtrlFBCANmessage использует следующие функции Vehicle Network Toolbox:

  • canSignalTimetable, чтобы вернуть расписание MATLAB, содержащее сигналы от сообщения CAN CruiseCtrlFB.

Запуск канала CAN

После создания экземпляра объекта Канала CAN app.canChannelObj и настройки сообщений для передачи и приема, теперь можно запустить канал. Когда пользователь нажимает кнопку start sim на пользовательском интерфейсе, мы хотим, чтобы канал стартовал непосредственно перед тем, как мы начнем запускать модель Simulink. Чтобы добиться этого, вспомогательная функция startSimApplication вызывается. startSimApplication, показанный в фрагменте кода ниже, проверяет, чтобы убедиться, что мы используем виртуальный канал CAN, потому что это единственный тип, который имеет смысл, если вы используете только симуляцию рабочего стола. Затем он проверяет, чтобы убедиться, что модель Simulink, с которой мы хотим соединиться, загружена в память с помощью bdIsLoaded команда. Если модель загружена и еще не работает, графики UI очищаются, чтобы принять новые данные сигнала, канал CAN запускается с помощью вспомогательной функции startCANChannel, и модель запускается.

function startSimApplication(app, index)
    % Start the model running on the desktop.
    
    % Check to see if hardware or virtual CAN channel is selected, otherwise do nothing.
    if app.canChannelInfo.DeviceModel(index) == "Virtual"
        % Check to see if the model is loaded before trying to run.
        if bdIsLoaded(app.mdl)
            % Model is loaded, now check to see if it is already running.
            if ~strcmp('running',get_param(app.mdl,'SimulationStatus'))
                % Model is not already running, so start it
                % flush the CAN Receive message buffers.
                app.tspeedFb = [];
                app.engagedFb = [];
                
                % Clear figure window.
                cla(app.tspeedPlot)
                cla(app.engagedPlot)
                
                % Start the CAN channels and update timer if it isn't already running.
                startCANChannel(app);
                
                % Start the model.
                set_param(app.mdl, 'SimulationCommand', 'start');
                
                % Set the sim start/stop button icon to the stop icon indicating the model has
                % been successfully started and is ready to be stopped at the next button press.
                app.SimStartStopButton.Icon = "IconEnd.png";
                app.StartSimLabel.Text = "Stop Sim";
            else
                % Model is already running, inform the user.
                warnStr = sprintf('Warning: Model %s is already running', app.mdl);
                warndlg(warnStr, 'Warning');
            end
        else
            % Model is not yet loaded, so warn the user.
            warnStr = sprintf('Warning: Model %s is not loaded\nPlease load the model and try again', app.mdl);
            warndlg(warnStr, 'Warning');
        end
    end
end

Функция помощника startCANChannel показан на фрагменте кода ниже. Эта функция проверяет, чтобы убедиться, что канал еще не запущен до его запуска. Затем он запускает объект-таймер MATLAB так, чтобы функция обратного вызова таймера receiveCANmsgsTimerCallback, описанный в предыдущем разделе, вызывается каждые 0,5 секунды для извлечения данных сообщения CAN из шины.

function startCANChannel(app)
    % Start the CAN channel if it isn't already running.
    try
        if ~app.canChannelObj.Running
            start(app.canChannelObj);
        end
    catch
        % do nothing.
    end
    
    % Start the CAN receive processing timer - check to see if it is already running. This allows us to change CAN channels
    % with or without starting and stopping the model running on the real time target.
    if strcmpi(app.receiveCANmsgsTimer.Running, 'off')
        start(app.receiveCANmsgsTimer);
    end
end

startCANchannel использует следующую функцию Vehicle Network Toolbox:

  • начало запуска Канала CAN. Канал будет оставаться в режиме on-line до тех пор, пока не будет выдана команда stop.

Остановите канал CAN

Когда пользователь нажимает кнопку stop sim на пользовательском интерфейсе, мы хотим остановить модель Simulink непосредственно перед остановкой канала CAN. Чтобы добиться этого, вспомогательная функция stopSimApplication вызывается. stopSimApplication, показанный в фрагменте кода ниже, проверяет, чтобы убедиться, что мы используем виртуальный канал CAN, потому что это единственный тип, который имеет смысл, если вы используете только симуляцию рабочего стола. Затем он останавливает модель Simulink и вызывает функцию helper stopCANChannel чтобы остановить канал CAN.

function stopSimApplication(app, index)
    % Stop the model running on the desktop.
    try
        % Check to see if hardware or virtual CAN channel is selected.
        if app.canChannelInfo.DeviceModel(index) == "Virtual"
            % Virtual channel selected, so issue a stop command to the
            % the simulation, even if it is already stopped.
            set_param(app.mdl, 'SimulationCommand', 'stop')
            
            % Stop the CAN channels and update timer.
            stopCANChannel(app);
        end
        
        % Set the sim start/stop button text to Start indicating the model has
        % been successfully stopped and is ready to start again at the next
        % button press.
        app.SimStartStopButton.Icon = "IconPlay.png";
        app.StartSimLabel.Text = "Start Sim";
    catch
        % Do nothing at the moment.
    end
end

Функция помощника stopCANChannel показан на фрагменте кода ниже. Эта функция останавливает канал CAN, затем останавливает объект-таймер MATLAB так, чтобы функция обратного вызова таймера receiveCANmsgsTimerCallback, описанный выше, больше не вызывается для извлечения сообщений из шины.

function stopCANChannel(app)
    % Stop the CAN channel.
    stop(app.canChannelObj);
    
    % Stop the CAN message processing timer.
    stop(app.receiveCANmsgsTimer);
end

stopCANchannel использует следующую функцию Vehicle Network Toolbox:

  • остановите, чтобы остановить канал CAN. Канал будет оставаться в автономном режиме до тех пор, пока не будет выдана другая команда start.

Добавление возможностей регистрации и воспроизведения CAN

На этом шаге мы опишем ключевые функции Vehicle Network Toolbox, используемые для добавления возможности входа, сохранения и воспроизведения сообщений CAN. Для реализации этой функциональности мы экземплярируем второй канал CAN, идентичный созданному первому. Поскольку второй объект канала CAN идентичен первому, он будет видеть и собирать те же сообщения, что и первый объект канала CAN. Второй канал CAN запускается, когда пользователь нажимает кнопку запуска логгирования на пользовательском интерфейсе, как показано на экране пользовательского интерфейса ниже. Канал продолжает запускать и собирать сообщения до тех пор, пока пользователь не нажмет кнопку stop logging на пользовательском интерфейсе. Как только пользователь перестанет регистрировать сообщения CAN, мы получим все сообщения, которые накопились в буфере сообщений для второго объекта канала CAN, извлечем сообщения, которые мы заинтересованы в воспроизведении, и сохраним их в .MAT файл. Как только сообщения были сохранены, мы можем воспроизвести их с помощью первого канала CAN, чтобы предоставить входу стимул модели Simulink Cruise Алгоритма управления в целях отладки и верификации алгоритмов.

В этом описании рассматриваются следующие темы:

  • Setup канала для регистрации сообщений CAN

  • Запуск и остановка канала

  • Получение и извлечение зарегистрированных сообщений CAN

  • Сохранение извлеченных сообщений в файл

  • Загрузка сохраненных сообщений из файла

  • Запуск воспроизведения зарегистрированных сообщений CAN

  • Остановите воспроизведение зарегистрированных сообщений CAN

Setup объекта Канала CAN в пользовательском интерфейсе для регистрации сообщений CAN

Способом, непосредственно аналогичным тому, как был создан первый канал CAN, форматированная строка конструктора канала CAN, сохраненная в app.canChannelConstructorSelected, используется новой вспомогательной функцией setupCANLogChannel чтобы создать второй образец объекта канала CAN, соедините тот же файл сети строения базы данных (.DBC), что и для первого канала, и установите скорость шины, как показано на фрагменте кода ниже. Получившийся объект канала хранится в свойстве UI app.canLogChannelObject.

function setupCANLogChannel(app)
    % Open CAN database file.
    db = canDatabase('CruiseControl.dbc');
    
    % Create a CAN channel for sending and receiving messages.
    app.canLogChannelObj = eval(app.canChannelConstructorSelected);
    
    % Attach CAN database to channel for received message decoding.
    app.canLogChannelObj.Database = db;
    
    % Set the baud rate (can only do this if the UI has channel initialization access).
    if app.canLogChannelObj.InitializationAccess
        configBusSpeed(app.canLogChannelObj, 500000);
    end
end

To see an example CAN database object, execute the following code:

db = canDatabase('CruiseControl.dbc')
db = 
  Database with properties:

             Name: 'CruiseControl'
             Path: '\\fs-01-mi\shome$\rollinb\Documents\MATLAB\Examples\vnt-ex00964061\CruiseControl.dbc'
            Nodes: {2×1 cell}
         NodeInfo: [2×1 struct]
         Messages: {2×1 cell}
      MessageInfo: [2×1 struct]
       Attributes: {'BusType'}
    AttributeInfo: [1×1 struct]
         UserData: []

To see an example CAN channel object, execute the following code:

% Instantiate the CAN channel object using the channel constructor string.
canLogChannelObj = eval(canChannelConstructor);

% Attach the CAN database to the channel object.
canLogChannelObj.Database = db
canLogChannelObj = 
  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: 0
        InitialTimestamp: [0×0 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: [1×1 can.Database]
                UserData: []

setupCANLogChannel использует следующие функции Vehicle Network Toolbox:

  • canChannel для создания экземпляров объекта канала с помощью команды eval и строки конструктора канала CAN, сохраненной в свойстве UI приложения app.canChannelConstructorSelected. Результирующий объект канала сохранен в свойстве UI приложения app.canLogChannelObj.

  • canDatabase для создания объекта базы данных CAN (.DBC), представляющего файл .DBC. Этот объект хранится в свойстве «Database» объекта канала.

Запуск журнала CAN

Как и в случае с первым каналом CAN, объект канала CAN app.canLogChannelOb был создан при открытии пользовательского интерфейса тестового приложения. Когда пользователь нажимает кнопку start Logging на пользовательском интерфейсе, как показано на экране, снятом выше, мы вызываем функцию helper startCANLogChannel, показанный в кодовом фрагменте ниже. Эта функция проверяет, работает ли второй канал CAN, и запускает его, если нет.

function startCANLogChannel(app)
    % Start the CAN Log channel if it isn't already running.
    try
        if ~app.canLogChannelObj.Running
            start(app.canLogChannelObj);
        end
    catch
        % Do nothing.
    end
end

startCANLogChannel использует следующую функцию Vehicle Network Toolbox:

  • начало запуска Канала CAN. Канал будет оставаться в оперативном режиме до тех пор, пока не будет выдана команда stop.

Остановка журнала CAN

Когда пользователь нажимает кнопку «Stop logging» на пользовательском интерфейсе, коллбэк кнопки вызывает функцию helper stopCANLogging, показан на фрагменте кода ниже. stopCANLogging останавливает канал CAN и извлекает все сообщения, накопленные во втором буфере канала, так как второй канал CAN был запущен пользователем нажатием кнопки «Начать логгирование».

function stopCANLogging(app)
    % Stop the CAN Log channel.
    stop(app.canLogChannelObj);
    
    % Get the messages from the CAN log message queue.
    retrieveLoggedCANMessages(app);
    
    % Update the button icon and label.
    app.canLoggingStartStopButton.Icon = 'IconPlay.png';
    app.StartLoggingLabel.Text = "Start Logging";
end

stopCANLogging использует следующую функцию Vehicle Network Toolbox:

  • остановите, чтобы остановить канал CAN. Канал будет оставаться в автономном режиме до тех пор, пока не будет выдана другая команда start.

Получение и извлечение записанных в журнал сообщений

Когда логгирующий канал CAN остановлен, функция helper retrieveLoggedCANMessages, показанный в фрагменте кода ниже, вызывается, чтобы извлечь все сообщения CAN от шины второго канала. Сообщения CAN получаются от шины второго канала с помощью receive командно-логическое индексирование используется для извлечения сообщений «CruiseCtrlCmd» из всего расписания сообщений, возвращенного receive команда.

function retrieveLoggedCANMessages(app)
    try
        % Receive available CAN message
        % initialize buffer to make sure it is empty.
        app.canLogMsgBuffer = [];
        
        % Receive available CAN messages.
        msg = receive(app.canLogChannelObj, Inf, 'OutputFormat', 'timetable');
        
        % Fill the buffer with the logged Cruise Control Command CAN message data.
        app.canLogMsgBuffer = msg(msg.Name == "CruiseCtrlCmd", :);
    catch err
        disp(err.message)
    end
end

Чтобы увидеть сообщения, возвращенные из receive команда выглядит так, как в формате timetable, запустите следующий код:

% Queue periodic transmission of CAN messages to generate sample message data once the channel starts.
cruiseControlFbMessage = canMessage(db, 'CruiseCtrlFB');
transmitPeriodic(canChannelObj, cruiseControlFbMessage, 'On', 0.1);
transmitPeriodic(canChannelObj, cruiseControlCmdMessage, 'On', 0.1);

% Start the first channel.
start(canChannelObj);

% Start the second (logging) channel.
start(canLogChannelObj);

% Wait 1 second to allow time for some messages to be generated on the bus.
pause(1);

% Stop the channels.
stop(canChannelObj)
stop(canLogChannelObj)

% Retrieve all messages from the logged message bus and output the results as a timetable.
msg = receive(canLogChannelObj, Inf, 'OutputFormat','timetable')
msg=20×8 timetable
        Time        ID     Extended          Name              Data        Length      Signals       Error    Remote
    ____________    ___    ________    _________________    ___________    ______    ____________    _____    ______

    0.077716 sec    256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.07772 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.1777 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.17771 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.27673 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.27674 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.37673 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.37674 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.47773 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.47773 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.57674 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.57674 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.67673 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.67673 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.77771 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.77771 sec     512     false      {'CruiseCtrlFB' }    {1×2 uint8}      2       {1×1 struct}    false    false 
      ⋮

% Extract only the Cruise Control Command CAN messages.
msgCmd = msg(msg.Name == "CruiseCtrlCmd", :)
msgCmd=10×8 timetable
        Time        ID     Extended          Name              Data        Length      Signals       Error    Remote
    ____________    ___    ________    _________________    ___________    ______    ____________    _____    ______

    0.077716 sec    256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.1777 sec      256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.27673 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.37673 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.47773 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.57674 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.67673 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.77771 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.87776 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 
    0.97769 sec     256     false      {'CruiseCtrlCmd'}    {1×2 uint8}      2       {1×1 struct}    false    false 

retrieveLoggedCANMessages использует следующие функции Vehicle Network Toolbox:

  • получите для извлечения сообщений CAN из шины CAN. В этом случае функция сконфигурирована для извлечения всех сообщений с момента предыдущего вызова и вывода результатов в виде расписания MATLAB.

Сохранение сообщений в файл

Когда пользователь нажимает кнопку «Save Logged Data» на пользовательском интерфейсе, функция helper saveLoggedCANDataToFile вызывается. Эта функция открывает окно браузера файлов с помощью uinputfile функция. uinputfile возвращает имя файла и путь, выбранные пользователем для хранения записанных данных сообщения CAN. Функция Vehicle Network Toolbox canMessageReplayBlockStruct используется для преобразования сообщений CAN из расписания MATLAB в форму, которую может использовать блок CAN Replay. После преобразования и сохранения зарегистрированных данных сообщений CAN в файл их можно отозвать и воспроизвести позже с помощью блока «Replay» Simulink Vehicle Network Toolbox. Чтобы воспроизвести сообщения в MATLAB с помощью Vehicle Network Toolbox с replay команда, само расписание передается как вход в функцию.

function savedLoggedCANDataToFile(app)
    % Raise dialog box to prompt user for a CAN log file to store the logged data.
    [FileName,PathName] = uiputfile('*.mat','Select a .MAT file to store logged CAN data');

    if FileName ~= 0
        % User did not cancel the file selection operation, so OK to save
        % convert the CAN log data from Timetable to struct of arrays so the data is compatible
        % with the VNT Simulink Replay block.
        canLogStructOfArrays = canMessageReplayBlockStruct(app.canLogMsgBuffer);
        save(fullfile(PathName, FileName), 'canLogStructOfArrays');

        % Clear the buffer after saving it.
        app.canLogMsgBuffer = [];
    end
end

saveLoggedCANDataToFile использует следующую функцию Vehicle Network Toolbox:

  • canMessageReplayBlockStruct для преобразования сообщений CAN, хранящихся в расписании MATLAB, в форму, которая может использоваться Блоком воспроизведения сообщений CAN.

Загрузка сообщений из файла

Когда пользователь нажимает кнопку «Load Logged Data» на пользовательском интерфейсе, функция helper loadLoggedCANDataFromFile вызывается. Эта функция открывает окно браузера файлов с помощью uigetfile функция, которая возвращает имя файла зарегистрированного сообщения, выбранное пользователем. Зарегистрированные данные сообщения CAN загружаются из файла и преобразуются обратно в представление расписания для использования с Vehicle Network Toolbox replay команда. Обратите внимание, что тот же файл данных может использоваться непосредственно с блоком Vehicle Network Toolbox «Replay» Simulink, если пользователь желает воспроизвести данные из модели Simulink. Можно принять решение воспроизвести данные с помощью блока «Replay» вместо из пользовательского интерфейса с помощью replay команда, поскольку блок «Replay» работает с отладчиком Simulink, останавливая воспроизведение, когда симуляция останавливается на точке остановки. The replay команда, напротив, не распознает, когда модель Simulink останавливается на точке останова, и просто продолжала бы воспроизводить сохраненные данные сообщения из файла. В целях примера мы будем воспроизводить данные с помощью replay команда.

function loadLoggedCANDataFromFile(app)
    % Raise dialog box to prompt user for a CAN log file to load.
    [FileName,PathName] = uigetfile('*.mat','Select a CAN log file to load');
    
    % Return focus to main UI after dlg closes.
    figure(app.UIFigure)
    
    if FileName ~= 0
        % User did not cancel the file selection operation, so OK to load
        % make sure the message buffer is empty before loading in the logged CAN data.
        app.canLogMsgBuffer = [];
        
        % Upload the saved message data from the selected file.
        canLogMsgStructOfArrays = load(fullfile(PathName, FileName), 'canLogStructOfArrays');
        
        % Convert the saved message data into timetables for the replay command.
        app.canLogMsgBuffer = canMessageTimetable(canLogMsgStructOfArrays.canLogStructOfArrays);
    end
end

loadLoggedCANDataFromFile использует следующую функцию Vehicle Network Toolbox:

  • canMessageTimetable для преобразования сообщений CAN, хранящихся в форме, совместимой с сообщением CAN «Replay», Блока Simulink обратно в расписание MATLAB для использования со replay функция.

Запуск воспроизведения записанных сообщений

После того, как зарегистрированные данные сообщения CAN были загружены в пользовательский интерфейс и переформатированы, они готовы к воспроизведению с помощью replay Vehicle Network Toolbox команда. Когда пользователь нажимает кнопку «Начать воспроизведение» на пользовательском интерфейсе, функция helper startPlaybackOfLoggedCANData вызывается. В порядок воспроизведения записанных данных сообщения CAN по первому каналу CAN вся активность, связанная с этим каналом, должна быть остановлена и все буферизированные данные сообщения очищены. Как показано на фрагменте кода ниже, startPlaybackOfLoggedCANData отключает периодическую передачу сообщений CAN, останавливает канал CAN, очищает любые данные сообщений CAN, буферизованные в пользовательском интерфейсе, и очищает графики, отображающие данные сигнала, поступающие обратно из модели алгоритма круиз-контроля. Затем канал CAN перезапускается, и записанные данные сообщения CAN воспроизводятся.

function startPlaybackOfLoggedCANData(app)
    % Turn off periodic transmission of CruiseCtrlCmd CAN message from UI controls.
    transmitPeriodic(app.canChannelObj, app.cruiseControlCmdMessage, 'Off');
    
    % Stop the UI CAN channel so we can instead use if for playback.
    stopCANChannel(app)
    
    % Flush the existing CAN messages stored for plotting.
    flushCANFbMsgQueue(app)
    
    % Clear the existing plots.
    cla(app.tspeedPlot)
    cla(app.engagedPlot)
    
    % Start the CAN Channel and replay the logged CAN message data.
    startCANChannel(app)
    
    % Replay the logged CAN data on the UI CAN Channel.
    replay(app.canChannelObj, app.canLogMsgBuffer);
end

startPlaybackOfLoggedCANData использует следующие функции Vehicle Network Toolbox:

  • transmitPeriodic для отключения периодической передачи командных сигналов, поступающих в модель алгоритма круиз-контроля в сообщении «CruiseCtrlCmd».

  • воспроизведение и воспроизведение записанных данных сообщения CAN на первом канале CAN.

Остановите воспроизведение записанных сообщений

Когда пользователь нажимает кнопку «Stop Replay» на пользовательском интерфейсе, функция helper stopPlaybackOfLoggedCANData вызывается. Для порядка остановки воспроизведения записанных данных сообщения CAN должен быть остановлен канал CAN, где воспроизводятся данные. После этого периодическая передача сообщения «CruiseCtrlCmd» может быть возобновлена, и канал перезапущен, так что пользователь снова сможет вводить сигналы тестового стимула в модель алгоритма круиз-контроля в интерактивном режиме из пользовательского интерфейса. Как показано на фрагменте кода ниже, stopPlaybackOfLoggedCANData сначала останавливает канал, который останавливает воспроизведение записанных данных сообщения. Записанные данные сообщения очищаются от локальных буферов на пользовательском интерфейсе, а также графиков, отображающих данные сигнала, подаваемые обратно из модели алгоритма круиз-контроля. Периодическая передача сообщения «CruiseCtrlCmd» переключается, и канал CAN перезапускается.

function stopPlaybackOfLoggedCANData(app)
    % Stop the playback CAN channel.
    stopCANChannel(app)
    
    % Flush the existing CAN messages stored for plotting.
    flushCANFbMsgQueue(app)
    
    % Clear the existing plots.
    cla(app.tspeedPlot)
    cla(app.engagedPlot)
    
    % Re-enable periodic transmission of CruiseCtrlCmd CAN message from UI controls.
    transmitPeriodic(app.canChannelObj, app.cruiseControlCmdMessage, 'On', 0.1);
    
    % Restart the CAN Channel from/To UI.
    startCANChannel(app)
end

stopPlaybackOfLoggedCANData использует следующие функции Vehicle Network Toolbox:

  • остановите, чтобы остановить канал CAN, чтобы остановить воспроизведение записанных данных сообщения CAN.

  • transmitPeriodic для повторного включения периодической передачи командных сигналов, отправляемых в модель алгоритма Круиз-контроля в сообщении «CruiseCtrlCmd».

  • начать перезапуск канала CAN, чтобы пользователь мог еще раз ввести сигналы тестового стимула в модель алгоритма круиз-контроля в интерактивном режиме из пользовательского интерфейса.

Добавление виртуальной канальной связи CAN к модели круиз- Алгоритм управления Simulink

На этом этапе мы опишем, как блоки Vehicle Network Toolbox Simulink использовались для добавления виртуальной коммуникационной возможности CAN к модели алгоритма Simulink Cruise Control.

В этом описании рассматриваются следующие темы:

  • Добавление функции получения сообщений CAN

  • Добавление возможности передачи сообщений CAN

  • Перемещение информации о строении канала CAN из пользовательского интерфейса в модель Simulink

Откройте модель Cruise Алгоритма управления Simulink

Запустите вспомогательные функции, чтобы сконфигурировать рабочую область с необходимыми параметрами данных, а затем откройте тестовую модель тестовой обвязки алгоритма Cruise Control. Когда модель Simulink открыта, можно исследовать фрагменты модели, объясненные в разделах ниже. Выполните helperPrepareTestBenchParameterData далее следуют helperConfigureAndOpenTestBench.

Добавление возможности получения сообщений CAN

Для модели Simulink алгоритма круиз-контроля для приема данных CAN из тестового пользовательского интерфейса требуется блок для подключения модели Simulink к конкретному устройству CAN, блок для приема сообщений CAN от выбранного устройства и блок для распаковки полезной нагрузки данных сообщений, полученных в отдельные сигналы. Для этого к модели Simulink алгоритма круиз-контроля добавляется подсистема «Входы». Подсистема «Inputs» использует строение Vehicle Network Toolbox, CAN Receive и CAN Unpack блоки, соединенные между собой, как показано на снимке экрана ниже.

Блок строения CAN позволяет пользователю определить, какие из доступных устройств и каналов CAN соединяются с моделью Simulink. Блок CAN Receive получает сообщения CAN от устройства CAN и канала, выбранных в блоке CAN Configuration. Это также позволяет пользователю принимать все сообщения на шине или применять фильтр для приема только выбранных сообщений. Блок CAN Unpack настроен для чтения пользовательского файла сетевой базы данных (DBC). Это позволяет пользователю определить имя сообщения, идентификатор сообщения и полезную нагрузку данных для распаковки сигналов с этим блоком. Входные порты Simulink автоматически добавляются к блоку для каждого сигнала, заданного в сообщении в файле сетевой базы данных.

Подсистема «Входы» Алгоритма управления Cruise модели Simulink использует следующие блоки Vehicle Network Toolbox Simulink для приема сообщений CAN:

  • CAN Configuration Block, чтобы выбрать устройство канала CAN для подключения к модели Simulink.

  • CAN Receive Block для приема сообщений CAN от устройства CAN, выбранного в блоке Строение.

  • CAN Unpack Block для распаковки полезной нагрузки полученного сообщения (сообщений) CAN в отдельные сигналы, по одному для каждого элемента данных, определенного в сообщении.

Добавление возможности передачи сообщений CAN

Для модели Simulink алгоритма круиз-контроля для передачи данных CAN в тестовый UI требуется блок для подключения модели Simulink к конкретному устройству CAN, блок для упаковки сигналов Simulink в полезную нагрузку данных одного или нескольких сообщений CAN и блок для передачи сообщений CAN от выбранного устройства. Для этого подсистема «Outputs» добавляется к модели Simulink алгоритма круиз-контроля. Подсистема «Выходов» использует блоки Vehicle Network Toolbox CAN pack и CAN Transmit, соединенные между собой, как показано на снимке экрана ниже.

Блок CAN Pack настроен для чтения пользовательского файла сетевой базы данных (DBC). Это позволяет пользователю определить имя сообщения, идентификатор сообщения и полезную нагрузку данных, чтобы упаковать сигнал с этим блоком. Выходные порты Simulink автоматически добавляются к блоку для каждого сигнала, заданного в сообщении в файле сетевой базы данных. Блок CAN Transmit передаст сообщение, собранное блоком Pack на канале CAN и устройстве CAN, выбранных пользователем с блоком Configuration. Обратите внимание, что второй блок строения CAN не требуется, поскольку подсистема «Outputs» передает сообщения CAN по тому же каналу CAN и устройству, используемому для приема сообщений CAN.

Подсистема «Выходов» Алгоритма управления Cruise модели Simulink использует следующие блоки Vehicle Network Toolbox Simulink для передачи сообщений CAN:

  • Блок CAN Pack для распаковки полезной нагрузки полученного сообщения (сообщений) CAN в отдельные сигналы, по одному для каждого элемента данных, определенного в сообщении.

  • CAN Transmit Block для приема сообщений CAN от устройства CAN, выбранного в блоке Строение.

Перемещение строения канала CAN из пользовательского интерфейса в модель Simulink

Поскольку пользователь выбирает, какие из доступных CAN-устройств и каналов использовать из пользовательского интерфейса, эта информация должна быть отправлена в модель Simulink алгоритма круиз-контроля, чтобы сохранить строения CAN-устройства и канала между UI и моделью Simulink в синхронизации. Для порядка этого необходимо программно сконфигурировать устройство CAN и информацию о канале, используемые блоками Vehicle Network Toolbox «CAN Строения», «CAN Transmit» и «CAN Receive». Каждый раз, когда пользователь выбирает устройство CAN и канал CAN из меню UI «Channel Configuration/Select CAN Channel», вспомогательная функция updateModelWithSelectedCANChannel вызывается. Как показано на фрагменте кода ниже, updateModelWithSelectedCANChannel находит путь блока для блоков «CAN Configuration», «CAN Transmit» и «CAN Receive» в рамках модели Simulink алгоритма круиз-контроля. Используя set_param команды, свойства блоков «Device», «DeviceMenu» и «ObjConstructor» для каждого из этих трех блоков устанавливаются в соответствующие свойства из выбранных пользователем устройства CAN и канала CAN.

function updateModelWithSelectedCANChannel(app, index)
    % Check to see if we are using a virtual CAN channel and whether the model is loaded.
    if app.canChannelInfo.DeviceModel(index) == "Virtual" && bdIsLoaded(app.mdl)
        % Using a virtual channel.
        
        % Find path to CAN configuration block.
        canConfigPath = find_system(app.mdl,'Variants', 'AllVariants', 'LookUnderMasks', 'all',...
            'FollowLInks', 'on', 'Name', 'CAN Configuration');
        
        % Find path to CAN transmit block.
        canTransmitPath = find_system(app.mdl,'Variants', 'AllVariants', 'LookUnderMasks', 'all',...
            'FollowLInks', 'on', 'Name', 'CAN Transmit');
        
        % Find path to CAN receive block.
        canReceivePath = find_system(app.mdl,'Variants', 'AllVariants', 'LookUnderMasks', 'all',...
            'FollowLInks', 'on', 'Name', 'CAN Receive');
        
        % Push the selected CAN channel into the simulation model CAN Configuration block.
        set_param(canConfigPath{1}, 'Device', app.canChannelDeviceSelected);
        set_param(canConfigPath{1}, 'DeviceMenu', app.canChannelDeviceSelected);
        set_param(canConfigPath{1}, 'ObjConstructor', app.canChannelConstructorSelected);
        
        % Push the selected CAN channel into the simulation model CAN Receive block.
        set_param(canReceivePath{1}, 'Device', app.canChannelDeviceSelected);
        set_param(canReceivePath{1}, 'DeviceMenu', app.canChannelDeviceSelected);
        set_param(canReceivePath{1}, 'ObjConstructor', app.canChannelConstructorSelected);
        
        % Push the selected CAN channel into the simulation model CAN Transmit block.
        set_param(canTransmitPath{1}, 'Device', app.canChannelDeviceSelected);
        set_param(canTransmitPath{1}, 'DeviceMenu', app.canChannelDeviceSelected);
        set_param(canTransmitPath{1}, 'ObjConstructor', app.canChannelConstructorSelected);
    end
end

Использование пользовательского интерфейса и модели вместе

При открытой модели и пользовательском интерфейсе можно исследовать взаимодействие с моделью в пользовательском интерфейсе. Нажмите «Start Sim», чтобы перевести модель и пользовательский интерфейс в оперативный режим. Экспериментируйте с разделами «Драйвер входы» и «Калибровки» УИ, чтобы контролировать модель и привести в действие круиз- алгоритм управления. Вы увидите зацепление круиз-контроля и значения скорости, построенные в пользовательском интерфейсе. Можно также использовать функции логгирования и воспроизведения, описанные ранее, с помощью элементов управления пользовательского интерфейса.

Создание пользовательского интерфейса таким образом дает вам мощный и гибкий тестовый интерфейс, настраиваемый под ваше приложение. Это ценно при отладке и оптимизации вашего алгоритма в симуляции. Путем изменения выбранного устройства CAN с виртуальных каналов на физические каналы, можно продолжать использовать UI для взаимодействия с алгоритмом, выполняемым в платформе быстрого прототипирования или целевом контроллере.