このページは機械翻訳を使用して翻訳されました。最新版の英語を参照するには、ここをクリックします。
CANを使用してSimulinkモデルのアプリを開発する
この例では、App Designer を使用してテスト アプリケーションのユーザー インターフェイス (UI) を構築し、仮想 CAN チャネルを使用してそれを Simulink ® モデルに接続する方法を示します。
テスト アプリケーション UI は、自動車クルーズ コントロール アプリケーションの Simulink モデルに仮想 CAN バス インターフェイスを提供するために、MATLAB ® App Designer といくつかの Vehicle Network Toolbox ™ 関数を使用して構築されます。テスト アプリケーション UI を使用すると、ユーザーはクルーズ コントロール アルゴリズム モデルに入力刺激を提供し、モデルからフィードバックされた結果を観察し、CAN メッセージをログに記録してテスト刺激をキャプチャし、ログに記録された CAN メッセージを再生してアルゴリズム モデルの問題をデバッグおよび修正できます。この例では、次の領域で CAN 通信を実装するために使用される主要な Vehicle Network Toolbox 関数とブロックを示します。
CAN経由でテストするためのSimulinkアルゴリズムモデルとの通信をサポートするテストアプリケーションUI
CANデータのログ記録と再生をサポートするテストアプリケーションUI
Simulinkアルゴリズムモデル

UIに仮想CANチャネル通信を追加する
このセクションでは、Simulink クルーズ コントロール アルゴリズム テスト アプリケーション モデルに CAN チャネル インターフェイスを追加するために使用される主要な Vehicle Network Toolbox 関数について説明します。これには次のトピックが含まれます。
利用可能なCANチャネルのリストを取得する
チャネル作成のためのチャネル情報のフォーマット
UIでチャネルを作成する
CANメッセージを送受信するためのUIを構成する
チャネルの開始と停止
選択したメッセージの抽出
App Designer を開く
App Designer でテスト アプリケーション UI を開きます。App Designer でテスト アプリケーション UI を開いた状態で、「デザイン」ビューと「コード」ビューを切り替えて、コントロールと対応する MATLAB コードを調べ、仮想 CAN チャネルを介して Simulink クルーズ コントロール アルゴリズム モデルと通信することができます。
準備スクリプトを実行して必要なデータを事前にロードし、App Designer を開いてテスト アプリを開発します。
helperPrepareTestBenchParameterData;
appdesigner('CruiseControlTestUI.mlapp')利用可能なCANチャネルの一覧
まず、ユーザーが選択できる利用可能な CAN チャネルのリストを検索して表示するメカニズムを実装します。このため、テスト アプリケーション UI の左上隅に「チャネル構成」メニュー項目を追加しました。「CAN チャネルの選択」サブメニューがあります。

ユーザーが CAN チャネルの選択 サブメニューをクリックすると、サブメニュー コールバックを介してヘルパー関数 getAvailableCANChannelInfo(app) が呼び出されます。次のコードに示すように、getAvailableCANChannelInfo() は Vehicle Network Toolbox 関数 canChannelList を使用して利用可能な 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=4×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" "Virtual 1" 1 "Virtual" "CAN, CAN FD" "100"
"Vector" "Virtual 1" 2 "Virtual" "CAN, CAN FD" "100"
canChannelList から返されたチャネルのリストは UI プロパティ app.canChannelInfo に保存され、上記のように表示されます。
チャネル設定用のチャネルリストのフォーマット
ユーザーは、「CAN チャネル選択」listdlg から CAN チャネルを選択します。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 に保存され、後でアプリケーション UI で選択された CAN チャネル オブジェクトを作成するために、また Simulink クルーズ コントロール アルゴリズム モデルで CAN チャネル インターフェイスを実装する Vehicle Network Toolbox Simulink ブロックを更新するために使用されます。
UIでCANチャネルを作成する
UI が最初に開かれて使用されると、app.canChannelConstructorSelected に格納されているフォーマット済みの CAN チャネル コンストラクター文字列がヘルパー関数 setupCANChannel によって使用され、CAN チャネル オブジェクトのインスタンスが作成され、ネットワーク構成データベース (.dbc) ファイルに接続され、次のコード フラグメントに示すようにバス速度が設定されます。結果のチャネル オブジェクトは、UI プロパティ app.canChannelObj に保存されます。
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
CAN データベース オブジェクトの例を表示するには、次のコマンドを実行します。
db = canDatabase('CruiseControl.dbc')db =
Database with properties:
Name: 'CruiseControl'
Path: 'C:\Users\jvijayak\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\jvijayak.Bdoc23b.j2277816\vnt-ex00964061\CruiseControl.dbc'
UTF8_File: 'C:\Users\jvijayak\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\jvijayak.Bdoc23b.j2277816\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: []
CAN チャネル オブジェクトの例を表示するには、次のコマンドを実行します。
% 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 コマンドと、アプリ UI プロパティapp.canChannelConstructorSelectedに保存されている CAN チャネル コンストラクター文字列を使用して、チャネル オブジェクトをインスタンス化します。結果のチャネル オブジェクトは、アプリ UI プロパティapp.canChannelObj. に保存されます。canDatabaseを使用して、DBC ファイルを表す CAN データベース (.dbc) オブジェクトを作成します。このオブジェクトは、チャネル オブジェクトのDatabaseプロパティに格納されます。
CANメッセージを送信するためのセットアップ
選択した CAN チャネル オブジェクトを設定し、それを UI プロパティ app.canChannelObj に保存したら、次のステップでは、以下のコード フラグメントに示すように、ヘルパー関数 setupCANTransmitMessages を呼び出します。setupCANTransmitMessages は、UI から送信する CAN メッセージを定義し、メッセージ ペイロードに信号を入力し、各信号に値を割り当て、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
CAN メッセージ オブジェクトがどのようになっているかを確認するには、次のコマンドを実行します。
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 秒ごと) で定期的に送信するためにキューに入れます。
CANメッセージを受信するための設定
UI は、Simulink モデル内のクルーズ コントロール アルゴリズムからのフィードバックを使用してプロットを更新するために、定期的に CAN メッセージを受信する必要があります。これを実現するには、まずこのコード フラグメントに示すように、MATLAB タイマー オブジェクトを作成します。
% create a timer to receive CAN msgs app.receiveCANmsgsTimer = timer('Period', 0.5,... 'ExecutionMode', 'fixedSpacing', ... 'TimerFcn', @(~,~)receiveCANmsgsTimerCallback(app));
タイマー オブジェクトは、0.5 秒ごとにタイマー コールバック関数 receiveCANmsgsTimerCallback を呼び出します。以下のコード フラグメントに示されている receiveCANmsgsTimerCallback は、バスからすべての CAN メッセージを取得し、ヘルパー関数 getCruiseCtrlFBCANmessage を使用して、クルーズ コントロール アルゴリズム モデルからフィードバックされた CAN メッセージを抽出し、抽出された CAN メッセージ データで UI プロットを更新します。
% 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=10×8 timetable
Time ID Extended Name Data Length Signals Error Remote
____________ ___ ________ _________________ _______ ______ ____________ _____ ______
0.016169 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.12518 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.23315 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.34315 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.45114 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.56016 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.6692 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.77918 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.88211 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.98119 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
% Stop the channel.
stop(canChannelObj)receiveCANmsgsTimerCallback は次の Vehicle Network Toolbox 関数を使用します。
receiveは CAN バスから CAN メッセージを取得します。この場合、関数は前回の呼び出し以降のすべてのメッセージを取得し、結果を MATLAB timetable として出力するように構成されています。
選択した CAN メッセージを抽出
ヘルパー関数 getCruiseCtrlFBCANmessage は、取得したすべての CAN メッセージから「CruiseCtrlFB」メッセージを除外し、これらのメッセージから tspeedFb 信号と engagedFb 信号を抽出し、これらを tspeedFb 信号と engagedFb 信号の MATLAB 時系列オブジェクトに連結します。これらの時系列オブジェクトは、それぞれ UI プロパティ app.tspeedFb と app.engagedFb に保存されます。保存された時系列信号は、UI 上の各信号のプロットを更新するために使用されます。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は、CAN メッセージ CruiseCtrlFB. からの信号を含む MATLAB timetable を返します。
CANチャネルを開始する
CAN チャネル オブジェクト app.canChannelObj がインスタンス化され、メッセージの送受信が設定されたら、チャネルを開始できます。ユーザーが UI で Start Sim をクリックしたときに、Simulink モデルの実行を開始する直前にチャネルが開始されるようにします。これを実現するために、ヘルパー関数 startSimApplication が呼び出されます。以下のコード フラグメントに示されている startSimApplication は、仮想 CAN チャネルを使用しているかどうかを確認します。これは、デスクトップ シミュレーションのみを使用している場合に意味をなす唯一のタイプであるためです。次に、bdIsLoaded コマンドを使用して、接続する Simulink モデルがメモリにロードされているかどうかを確認します。モデルがロードされ、まだ実行されていない場合は、新しい信号データを受け入れるために UI プロットがクリアされ、ヘルパー関数 startCANChannel を使用して CAN チャネルが開始され、モデルが開始されます。
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 関数を使用します。
startは CAN チャネルの実行を開始します。stopコマンドが発行されるまで、チャネルはオンラインのままになります。
CANチャネルを停止する
ユーザーが UI で Stop Sim をクリックしたときに、CAN チャネルを停止する直前に Simulink モデルを停止します。これを実現するために、ヘルパー関数 stopSimApplication が呼び出されます。以下のコード フラグメントに示されている stopSimApplication は、仮想 CAN チャネルを使用しているかどうかを確認します。これは、デスクトップ シミュレーションのみを使用している場合に意味をなす唯一のタイプであるためです。次に、Simulink モデルを停止し、ヘルパー関数 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 関数を使用します。
stopは CAN チャネルを停止します。別のstartコマンドが発行されるまで、チャネルはオフラインのままになります。
CANログと再生機能の追加
このステップでは、CAN メッセージをログに記録、保存、再生する関数を追加するために使用される主要な Vehicle Network Toolbox 関数について説明します。この機能を実装するには、最初に作成したものと同じ 2 番目の CAN チャネルをインスタンス化します。2 番目の CAN チャネル オブジェクトは最初のオブジェクトと同一であるため、最初の CAN チャネル オブジェクトと同じメッセージを表示および収集します。ユーザーが UI で ログ記録の開始 をクリックすると、2 番目の CAN チャネルが開始されます。ユーザーが ログの停止 をクリックするまで、チャネルは実行され、メッセージの収集を継続します。ユーザーが CAN メッセージのログ記録を停止すると、2 番目の CAN チャネル オブジェクトのメッセージ バッファーに蓄積されたすべてのメッセージを取得し、再生するメッセージを抽出して、MAT ファイルに保存します。メッセージが保存されると、最初の CAN チャネルを使用してメッセージを再生し、デバッグとアルゴリズムの検証のために Simulink クルーズ コントロール アルゴリズム モデルに入力刺激を提供できます。

この説明では、次のトピックについて説明します。
CANメッセージをログに記録するためのチャネルを設定する
チャネルの開始と停止
記録されたCANメッセージの取得と抽出
抽出したメッセージをファイルに保存する
ファイルから保存したメッセージを読み込む
記録されたCANメッセージの再生を開始する
記録されたCANメッセージの再生を停止する
UI で CAN チャネル オブジェクトを設定して CAN メッセージをログに記録する
最初の CAN チャネルがインスタンス化された方法とまったく同じように、app.canChannelConstructorSelected に格納されているフォーマット済みの CAN チャネル コンストラクター文字列が新しいヘルパー関数 setupCANLogChannel によって使用され、CAN チャネル オブジェクトの 2 番目のインスタンスが作成され、最初のチャネルに使用されたのと同じネットワーク構成データベース (.dbc) ファイルに接続され、以下のコード フラグメントに示すようにバス速度が設定されます。結果のチャネル オブジェクトは UI プロパティ app.canLogChannelObj に保存されます。
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
CAN データベース オブジェクトの例を確認するには、次のコードを実行します。
db = canDatabase('CruiseControl.dbc')db =
Database with properties:
Name: 'CruiseControl'
Path: 'C:\Users\jvijayak\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\jvijayak.Bdoc23b.j2277816\vnt-ex00964061\CruiseControl.dbc'
UTF8_File: 'C:\Users\jvijayak\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\jvijayak.Bdoc23b.j2277816\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: []
CAN チャネル オブジェクトの例を表示するには、次のコードを実行します。
% 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 コマンドと、アプリ UI プロパティapp.canChannelConstructorSelectedに保存されている CAN チャネル コンストラクター文字列を使用して、チャネル オブジェクトをインスタンス化します。結果のチャネル オブジェクトは、アプリ UI プロパティapp.canLogChannelObj. に保存されます。canDatabaseは、DBC ファイルを表す CAN データベース (.dbc) オブジェクトを作成します。このオブジェクトは、チャネル オブジェクトのDatabaseプロパティに格納されます。
CANログチャネルを開始する
最初の CAN チャネルと同様に、テスト アプリケーション UI が開かれると、CAN チャネル オブジェクト app.canLogChannelObj がインスタンス化されます。ユーザーが ログ記録を開始 をクリックすると、以下のコードに示すように、ヘルパー関数 startCANLogChannel が呼び出されます。この関数は、2 番目の 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 関数を使用します。
startを実行して CAN チャネルの実行を開始します。チャネルは、stopコマンドが発行されるまでオンラインのままになります。
CANログチャネルを停止する
ユーザーが UI で ログ記録の停止 をクリックすると、ボタンのコールバックによって、以下のコード フラグメントに示すヘルパー関数 stopCANLogging が呼び出されます。stopCANLogging は CAN チャネルを停止し、ユーザーが ログ記録の開始 をクリックして 2 番目の CAN チャネルを開始してから 2 番目のチャネル バッファーに蓄積されたすべてのメッセージを取得します。
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 関数を使用します。
stopは CAN チャネルを停止します。別の start コマンドが発行されるまで、チャネルはオフラインのままになります。
ログに記録されたメッセージの取得と抽出
ログ記録 CAN チャネルが停止されると、以下のコード フラグメントに示すヘルパー関数 retrieveLoggedCANMessages が呼び出され、2 番目のチャネル バスからすべての CAN メッセージを取得します。CAN メッセージは、receive コマンドを使用して 2 番目のチャネル バスから取得され、論理インデックスを使用して、receive コマンドによって返されたすべての message timetable から "CruiseCtrlCmd" メッセージが抽出されます。
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=52×8 timetable
Time ID Extended Name Data Length Signals Error Remote
____________ ___ ________ _________________ _______ ______ ____________ _____ ______
0.073091 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.073094 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
0.18515 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.18515 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
0.29512 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.29513 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
0.40412 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.40413 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
0.51208 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.51208 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
0.62109 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.62109 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
0.73113 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.73113 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
0.83307 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.83307 sec 512 false {'CruiseCtrlFB' } {[0 0]} 2 {1×1 struct} false false
⋮
% Extract only the Cruise Control Command CAN messages. msgCmd = msg(msg.Name == "CruiseCtrlCmd", :)
msgCmd=26×8 timetable
Time ID Extended Name Data Length Signals Error Remote
____________ ___ ________ _________________ _______ ______ ____________ _____ ______
0.073091 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.18515 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.29512 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.40412 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.51208 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.62109 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.73113 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.83307 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
0.9331 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
1.0431 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
1.1531 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
1.2631 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
1.3703 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
1.4776 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
1.5872 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
1.6972 sec 256 false {'CruiseCtrlCmd'} {[0 0]} 2 {1×1 struct} false false
⋮
retrieveLoggedCANMessages は次の Vehicle Network Toolbox 関数を使用します。
receiveは CAN バスから CAN メッセージを取得します。この場合、関数は前回の呼び出し以降のすべてのメッセージを取得し、結果を MATLAB timetable として出力するように構成されています。
メッセージをファイルに保存する
ユーザーが UI で ログデータを保存 をクリックすると、ヘルパー関数 saveLoggedCANDataToFile が呼び出されます。この関数は、uinputfile 関数を使用してファイル ブラウザー ウィンドウを開きます。uinputfile は、ログに記録された CAN メッセージ データを保存するためにユーザーが選択したファイル名とパスを返します。Vehicle Network Toolbox 関数 canMessageReplayBlockStruct は、CAN メッセージを MATLAB timetable から CAN Replay ブロックが使用できる形式に変換するために使用されます。記録された CAN メッセージ データが変換されファイルに保存されると、後で Vehicle Network Toolbox「再生」Simulink ブロックを使用して呼び出して再生できます。replay コマンドを使用して MATLAB 内のメッセージを Vehicle Network Toolbox で再生するには、timetable 自体が関数への入力として渡されます。
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は、MATLAB timetable に保存されている CAN メッセージを、CAN メッセージ再生ブロックで使用できる形式に変換します。
ファイルからメッセージを読み込む
ユーザーが UI で ログ データの読み込み をクリックすると、ヘルパー関数 loadLoggedCANDataFromFile が呼び出されます。この関数は、uigetfile 関数を使用してファイル ブラウザー ウィンドウを開き、ユーザーが選択したログ メッセージのファイル名を返します。記録された CAN メッセージ データはファイルから読み込まれ、Vehicle Network Toolbox replay コマンドで使用するために timetable 表現に変換されます。ユーザーが Simulink モデルからデータを再生したい場合は、同じデータ ファイルを Vehicle Network Toolbox Replay Simulink ブロックで直接使用できることに注意してください。Replay ブロックは Simulink デバッガーと連携して動作し、シミュレーションがブレークポイントで停止すると再生を一時停止するため、UI から replay コマンドを使用する代わりに、Replay ブロックを使用してデータを再生することを選択できます。対照的に、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 メッセージ Replay Simulink ブロックと互換性のある形式で保存された CAN メッセージを、replay関数で使用するために MATLAB timetable に変換します。
記録されたメッセージの再生を開始する
ログに記録された CAN メッセージ データが UI にロードされ、再フォーマットされたら、Vehicle Network Toolbox replay コマンドを使用して再生できるようになります。ユーザーが UI で 再生を開始 をクリックすると、ヘルパー関数 startPlaybackOfLoggedCANData が呼び出されます。最初の CAN チャネルを介して記録された CAN メッセージ データを再生するには、このチャネルに関連付けられたすべてのアクティビティを停止し、バッファリングされたメッセージ データをすべてクリアする必要があります。以下のコード フラグメントに示すように、startPlaybackOfLoggedCANData は CAN メッセージの定期的な送信をオフにし、CAN チャネルを停止し、UI にバッファリングされているすべての 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」メッセージでクルーズ コントロール アルゴリズム モデルに送信されるコマンド信号の定期的な送信を無効にします。replayは、最初の CAN チャネルで記録された CAN メッセージ データを再生します。
記録されたメッセージの再生を停止する
ユーザーが UI で 再生を停止 をクリックすると、ヘルパー関数 stopPlaybackOfLoggedCANData が呼び出されます。記録された CAN メッセージ データの再生を停止するには、データが再生されている CAN チャネルを停止する必要があります。これが完了すると、「CruiseCtrlCmd」メッセージの定期的な送信が再度有効になり、チャネルが再起動されるため、ユーザーは再び UI から対話的に Cruise Control アルゴリズム モデルにテスト刺激信号を注入できるようになります。以下のコード フラグメントに示すように、stopPlaybackOfLoggedCANData は最初にチャネルを停止し、ログに記録されたメッセージ データの再生を停止します。ログに記録されたメッセージ データは、UI 上のローカル バッファーからクリアされるだけでなく、クルーズ コントロール アルゴリズム モデルからフィードバックされた信号データを表示するプロットからもクリアされます。「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 関数を使用します。
stopは CAN チャネルを停止し、記録された CAN メッセージ データの再生を停止します。transmitPeriodicは、「CruiseCtrlCmd」メッセージでクルーズ コントロール アルゴリズム モデルに送信されるコマンド信号の定期的な送信を再度有効にします。startは CAN チャネルを再起動して、ユーザーが UI から対話形式で再度テスト刺激信号をクルーズ コントロール アルゴリズム モデルに注入できるようにします。
Simulink クルーズコントロールアルゴリズムモデルに仮想 CAN チャネル通信を追加する
このステップでは、Vehicle Network Toolbox Simulink ブロックを使用して、Simulink クルーズ コントロール アルゴリズム モデルに仮想 CAN 通信機能を追加する方法について説明します。

この説明では、次のトピックについて説明します。
CANメッセージ受信機能の追加
CANメッセージ送信機能の追加
UIからSimulinkモデルにCANチャネル構成情報をプッシュする
クルーズコントロールアルゴリズムSimulinkモデルを開く
ヘルパー関数を実行して、必要なデータ パラメータを使用してワークスペースを構成し、クルーズ コントロール アルゴリズム テスト ハーネス モデルを開きます。Simulink モデルを開くと、以下のセクションで説明されているモデルの部分を調べることができます。helperPrepareTestBenchParameterData に続いて helperConfigureAndOpenTestBench を実行します。
CANメッセージ受信機能の追加
クルーズ コントロール アルゴリズムの Simulink モデルがテスト UI から CAN データを受信するには、Simulink モデルを特定の CAN デバイスに接続するブロック、選択したデバイスから CAN メッセージを受信するブロック、受信したメッセージのデータ ペイロードを個々の信号にアンパックするブロックが必要です。これを実現するために、クルーズ コントロール アルゴリズム Simulink モデルに「入力」サブシステムが追加されます。「入力」サブシステムは、下のスクリーンショットに示すように、相互接続された Vehicle Network Toolbox CAN Configuratio、CAN Receive、および CAN Unpack ブロックを使用します。
CAN Configuration ブロックを使用すると、ユーザーは利用可能な CAN デバイスとチャネルのどれを Simulink モデルに接続するかを決定できます。CAN Receive ブロックは、CAN Configuration ブロックで選択された CAN デバイスとチャネルから CAN メッセージを受信します。また、ユーザーはバス上のすべてのメッセージを受信したり、フィルターを適用して選択したメッセージのみを受信したりすることもできます。CAN Unpack ブロックは、ユーザー定義のネットワーク データベース (.dbc) ファイルを読み取るように構成されています。これにより、ユーザーは、このブロックを使用して信号をアンパックするためのメッセージ名、メッセージ ID、およびデータ ペイロードを決定できます。Simulink 入力ポートは、ネットワーク データベース ファイル内のメッセージで定義された各信号のブロックに自動的に追加されます。

クルーズ コントロール アルゴリズム Simulink モデルの「入力」サブシステムは、次の Vehicle Network Toolbox Simulink ブロックを使用して CAN メッセージを受信します。
CAN Configuration ブロックは、Simulink モデルに接続する CAN チャネル デバイスを選択します。
CAN Receive ブロックは、CAN Configuration ブロックで選択された CAN デバイスから CAN メッセージを受信します。
CAN Unpack ブロックは、受信した CAN メッセージのペイロードを、メッセージで定義されているデータ項目ごとに 1 つずつ個別の信号にアンパックします。
CANメッセージ送信機能の追加
クルーズ コントロール アルゴリズムの Simulink モデルが CAN データをテスト UI に送信するには、Simulink モデルを特定の CAN デバイスに接続するブロック、Simulink 信号を 1 つ以上の CAN メッセージのデータ ペイロードにパックするブロック、および選択したデバイスから CAN メッセージを送信するブロックが必要です。これを実現するために、クルーズ コントロール アルゴリズム Simulink モデルに「出力」サブシステムが追加されます。「出力」サブシステムは、下のスクリーンショットに示すように、相互接続された Vehicle Network Toolbox CAN pack ブロックと CAN Transmit ブロックを使用します。
CAN Pack ブロックは、ユーザー定義のネットワーク データベース (.dbc) ファイルを読み取るように構成されています。これにより、ユーザーは、このブロックを使用して信号をパックするためのメッセージ名、メッセージ ID、およびデータ ペイロードを決定できます。ネットワーク データベース ファイル内のメッセージで定義された各信号のブロックに、Simulink 出力ポートが自動的に追加されます。CAN Transmit ブロックは、Pack ブロックによって組み立てられたメッセージを、ユーザーが Configuration ブロックで選択した CAN チャネルおよび CAN デバイスに送信します。"Outputs" サブシステムは、CAN メッセージの受信に使用されるのと同じ CAN チャネルおよびデバイスで CAN メッセージを送信するため、2 番目の CAN Configuration ブロックは必要ないことに注意してください。

クルーズ コントロール アルゴリズム Simulink モデルの "Outputs" サブシステムは、次の Vehicle Network Toolbox Simulink ブロックを使用して CAN メッセージを送信します。
CAN Pack ブロックは、受信した CAN メッセージのペイロードを、メッセージで定義されているデータ項目ごとに 1 つずつ個別の信号にアンパックします。
CAN Transmit ブロックは、CAN Configuration ブロックで選択された CAN デバイスから CAN メッセージを受信します。
UI から Simulink モデルに CAN チャネル設定をプッシュする
ユーザーは UI から使用可能な CAN デバイスとチャネルのどれを使用するかを選択するため、UI と Simulink モデル間の CAN デバイスとチャネルの構成を同期させるには、この情報を Cruise Control アルゴリズム Simulink モデルに送信する必要があります。これを実現するには、CAN Configuration、CAN Transmit、および CAN Receive ブロックで使用される CAN デバイスとチャネル情報を、UI からプログラムで構成する必要があります。ユーザーが UI の「チャネル構成/CAN チャネルの選択」メニューから CAN デバイスと CAN チャネルを選択するたびに、ヘルパー関数 updateModelWithSelectedCANChannel が呼び出されます。以下のコード フラグメントに示すように、updateModelWithSelectedCANChannel は、クルーズ コントロール アルゴリズム Simulink モデル内の CAN Configuration、CAN Transmit、および CAN Receive ブロックのブロック パスを見つけます。set_param コマンドを使用すると、これら 3 つのブロックのそれぞれに対する 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
UIとモデルを一緒に使う
モデルと UI の両方を開いた状態で、UI でモデルを操作する方法を試すことができます。シミュレーションを開始 をクリックして、モデルと UI をオンラインにします。UI の「ドライバー入力」セクションと「キャリブレーション」セクションを試して、モデルを制御し、クルーズ コントロール アルゴリズムを作動させます。クルーズ コントロールの作動と速度の値が UI に表示されます。UI コントロールを介して、前述のログ記録機能と再生機能を使用することもできます。
この方法で UI を作成すると、アプリケーションに合わせてカスタマイズできる強力で柔軟なテスト インターフェイスが提供されます。シミュレーションでアルゴリズムをデバッグおよび最適化するときに役立ちます。選択した CAN デバイスを仮想チャネルから物理チャネルに変更することで、引き続き UI を使用して、ラピッドプロトタイピング プラットフォームまたはターゲット コントローラで実行されているアルゴリズムと対話できます。