Интегрируйте код внешнего приложения с кодом, сгенерированным от ПИД-регулятора

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

Осмотрите внешний код

Установите свою текущую папку на перезаписываемое местоположение.

Скопируйте скрипт prepare_ext_code в вашу текущую папку и запустите скрипт. Скрипт копирует внешние файлы кода в несколько папок.

try
copyfile(fullfile(matlabroot,'examples','ecoder','main','prepare_ext_code.m'),...
    'prepare_ext_code.m','f');
catch
end
run('prepare_ext_code.m');

В вашей текущей папке откройте ext_code_main.c. Этот код приложения представляет встраиваемую систему с тривиальным алгоритмом планирования (цикл while) и три модуля чьи алгоритмы, запущенные в каждом цикле выполнения: ex_ext_inputs_proc, ex_ext_ctrl_alg и ex_ext_outputs_proc.

type('ext_code_main.c')

В папке shared осмотрите ex_ext_projTypes.h. Файл задает два пользовательских типа данных (typedef), который используют данные в модулях.

type(fullfile('shared','ex_ext_projTypes.h'))

В папке io_drivers осмотрите ex_sensor_accessors.c. Этот файл задает функции, get_fromSensor_flow и get_fromSensor_temp, которые возвращают необработанные данные, зарегистрированные датчиком потока и датчиком температуры. В данном примере функции возвращают тривиальные синусоидальные стимулы для алгоритма управления.

type(fullfile('io_drivers','ex_sensor_accessors.c'))

В папке ex_ext_inputs_proc осмотрите ex_ext_inputs_proc.c. Модуль ex_ext_inputs_proc считывает данные о датчике (путем вызывания функций средства доступа), фильтрует данные и хранит его в двух глобальных переменных, PROC_INPUT_FLOW и PROC_INPUT_TEMP. Эти глобальные переменные заданы в файле ex_ext_proc_inputs.c и объявлены в ex_ext_proc_inputs.h.

type(fullfile('ex_ext_inputs_proc','ex_ext_inputs_proc.c'))

Алгоритм фильтра в этом модуле и алгоритмы в других двух модулях требуют данных состояния, которые должны сохраниться между циклами выполнения приложения. Каждый модуль хранит соответствующие данные состояния как глобальные переменные. Например, в модуле ex_ext_inputs_proc, ex_ext_inputs_proc.c задает эти переменные:

  • flowFilterIn_state_data

  • tempFilterIn_state_data

  • flowFilterIn_tmp_data

  • tempFilterIn_tmp_data

Пустая папка ex_ext_ctrl_alg является заполнителем для сгенерированного кода. Модуль ex_ext_ctrl_alg должен выполнить управление ПИДом на отфильтрованных измерениях потока и измерениях температуры. Позже, вы исследуете требования на этот код, которые основаны на коде в других модулях.

В папке ex_ext_outputs_proc осмотрите ex_ext_outputs_proc.c. Этот модуль читает выходные сигналы ПИДа глобальных переменных под названием CONTR_SIG_FLOW и CONTR_SIG_TEMP. Модуль ex_ext_ctrl_alg (сгенерированный код) должен задать эти переменные. Модуль ex_ext_outputs_proc затем фильтрует эти сигналы и передает отфильтрованные значения функциям, которые представляют драйверы устройств для приводов (например, клапан и нить нагревателя).

type(fullfile('ex_ext_outputs_proc','ex_ext_outputs_proc.c'))

Функции привода заданы в папке io_drivers в файле ex_actuator_accessors.c.

Данные показывают намеченный поток данных через систему. Данные также показывают файлы кода, которые задают и объявляют данные (глобальные переменные), которые пересекают контуры модуля.

Осмотрите модель Simulink и определите требования для сгенерированного кода

Откройте модель ex_ext_ctrl_alg в качестве примера.

open_system('ex_ext_ctrl_alg')

Блоки в модели реализуют необходимый алгоритм управления ПИДа. Модель использует настройки генерации кода по умолчанию для основанного на ERT системного конечного файла (ert.tlc).

Чтобы заполнить заявление путем выполнения функции модуля ex_ext_ctrl_alg, код, сгенерированный из этой модели, должен:

  • Используйте пользовательские типы данных dataPath_flow_T и dataPath_temp_T из внешнего файла ex_ext_projTypes.h.

  • Считайте отфильтрованные данные о датчике из глобальных переменных PROC_INPUT_FLOW и PROC_INPUT_TEMP. Сгенерированный код не должен задавать эти переменные, потому что модуль ex_ext_inputs_proc задает их, объявляя их в ex_ext_proc_inputs.h.

  • Запишите управляющие сигналы ПИДа в глобальные переменные под названием CONTR_SIG_FLOW и CONTR_SIG_TEMP. Сгенерированный код должен задать эти переменные и объявить их в файле с именем ex_ext_ctrl_sigs.h. Затем модуль ex_ext_outputs_proc может считать необработанные управляющие сигналы от них.

  • Соответствуйте переменным стандартам именования, которые управляют внешним приложением. Например, сгенерированный код должен хранить данные состояния в глобальных переменных, имена которых заканчиваются в _data. Кроме того, для этого примера, имена переменных локальной функции должны закончиться в _local.

  • Соответствуйте стандартам, которые управляют организацией кода в каждом из внешних файлов. Например, каждый файл содержит разделы, разграниченные комментариями, тем совокупным подобным кодом построения, такие как определения типа, объявления переменной и функциональные определения.

Так, чтобы вы и другие могли взаимодействовать с алгоритмом управления во время выполнения для этого примера, вы также конфигурируете сгенерированный код, чтобы задать и объявить глобальные переменные const под названием PARAM_setpoint_flow и PARAM_setpoint_temp, которые представляют заданные значения ПИД-регулятора. Определения должны появиться в файле с именем, ex_ext_ctrl_params.c и объявления должны появиться в файле с именем ex_ext_ctrl_params.h.

Сконфигурируйте модель, чтобы использовать пользовательские типы данных

Установите свою текущую папку на папку shared.

Используйте функциональный Simulink.importExternalCTypes, чтобы сгенерировать объекты Simulink.AliasType, которые представляют пользовательские типы данных dataPath_flow_T и dataPath_temp_T.

cd('shared')
Simulink.importExternalCTypes('ex_ext_projTypes.h');

Объекты появляются в базовом рабочем пространстве.

В модели ex_ext_ctrl_alg выберите View> Model Data Editor.

В Model Data Editor, для блока Inport, который представляет PROC_INPUT_FLOW, Тип данных набора к dataPath_flow_T.

Для блока Inport, который представляет PROC_INPUT_TEMP, Тип данных набора к dataPath_temp_T.

Выберите вкладку Signals.

В модели выберите выходной сигнал каждого блока Constant. В Model Data Editor, Типе данных набора к Inherit: Inherit via back propagation. С этой установкой каждый блок Constant наследовал свой тип выходных данных от блока сразу в нисходящем направлении, в этом случае, блока Sum.

Также, чтобы сконфигурировать типы данных, в командной строке, используют эти команды.

set_param('ex_ext_ctrl_alg/In1','OutDataTypeStr','dataPath_flow_T')
set_param('ex_ext_ctrl_alg/In2','OutDataTypeStr','dataPath_temp_T')
set_param('ex_ext_ctrl_alg/Flow Setpt','OutDataTypeStr',...
    'Inherit: Inherit via back propagation')
set_param('ex_ext_ctrl_alg/Temp Setpt','OutDataTypeStr',...
    'Inherit: Inherit via back propagation')

Обновите блок-схему. Схема показывает что, из-за наследования типа данных и распространения, сигналов в использовании модели пользовательский тип данных.

Сконфигурируйте интерфейсные данные

Сконфигурируйте модель, чтобы сгенерировать код, что доступы и задают правильные глобальные переменные, такие как PROC_INPUT_FLOW и CONTR_SIG_TEMP.

В Model Data Editor выберите вкладку Inports/Outports и установите представление Change выпадающий список на Code.

Выберите строки, которые соответствуют двум блокам Inport.

Для любой строки, Класса памяти набора к ImportFromFile и Заголовочного файла к ex_ext_proc_inputs.h. С классом памяти ImportFromFile каждый блок Inport появляется в сгенерированном коде как глобальная переменная. Однако сгенерированный код не задает переменную, вместо этого включая (#include) объявление переменной от ex_ext_proc_inputs.h.

Для строк, которые соответствуют блокам Выходного порта, установите:

  • Класс памяти к ExportToFile

  • Заголовочный файл к ex_ext_ctrl_sigs.h

  • Файл определения к ex_ext_ctrl_sigs.c

С ExportToFile сгенерированный код задает глобальную переменную.

Также, чтобы сконфигурировать сигналы, в командной строке, используют эти команды.

temp = Simulink.Signal;
temp.CoderInfo.StorageClass = 'Custom';
temp.CoderInfo.CustomStorageClass = 'ImportFromFile';
temp.CoderInfo.CustomAttributes.HeaderFile = 'ex_ext_proc_inputs.h';

portHandles = get_param('ex_ext_ctrl_alg/In1','portHandles');
outportHandle = portHandles.Outport;
set_param(outportHandle,'SignalObject',copy(temp))

portHandles = get_param('ex_ext_ctrl_alg/In2','portHandles');
outportHandle = portHandles.Outport;
set_param(outportHandle,'SignalObject',copy(temp))

temp.CoderInfo.CustomStorageClass = 'ExportToFile';
temp.CoderInfo.CustomAttributes.HeaderFile = 'ex_ext_ctrl_sigs.h';
temp.CoderInfo.CustomAttributes.DefinitionFile = 'ex_ext_ctrl_sigs.c';

set_param('ex_ext_ctrl_alg/Out1','SignalObject',copy(temp))
set_param('ex_ext_ctrl_alg/Out2','SignalObject',copy(temp))

Чтобы применить класс памяти к параметрам блоков, таким как параметр Постоянного значения блока Constant, необходимо создать объект параметра, такой как Simulink.Parameter. Можно использовать Model Data Editor, чтобы создать объекты параметра.

Выберите вкладку Parameters и установите представление Change на Design.

В модели блок Constant выбор, маркировал Flow Setpt.

В Model Data Editor, установленном Значении к PARAM_setpoint_flow.

Рядом с PARAM_setpoint_flow кликните по кнопке действий (с тремя вертикальными точками) и выберите Create.

В диалоговом окне Create New Data, установленном Значении к Simulink.Parameter(3).

Установите Местоположение на Model Workspace и нажмите Create.

В диалоговом окне свойства PARAM_setpoint_flow, Классе памяти набора к Const.

Установите HeaderFile на ex_ext_ctrl_params.h и DefinitionFile к ex_ext_ctrl_params.c.

Для другого блока Constant используйте Model Data Editor, чтобы создать объект Simulink.Parameter под названием PARAM_setpoint_temp со значением 2.

Также, чтобы сконфигурировать блоки, в командной строке, используют эти команды.

PARAM_setpoint_flow = Simulink.Parameter(3);
PARAM_setpoint_flow.CoderInfo.StorageClass = 'Custom';
PARAM_setpoint_flow.CoderInfo.CustomStorageClass = 'Const';
PARAM_setpoint_flow.CoderInfo.CustomAttributes.HeaderFile = 'ex_ext_ctrl_params.h';
PARAM_setpoint_flow.CoderInfo.CustomAttributes.DefinitionFile = 'ex_ext_ctrl_params.c';

PARAM_setpoint_temp = copy(PARAM_setpoint_flow);
PARAM_setpoint_temp.Value = 2;

mdlwks = get_param('ex_ext_ctrl_alg','ModelWorkspace');
assignin(mdlwks,'PARAM_setpoint_flow',copy(PARAM_setpoint_flow))
assignin(mdlwks,'PARAM_setpoint_temp',copy(PARAM_setpoint_temp))

set_param('ex_ext_ctrl_alg/Flow Setpt','Value','PARAM_setpoint_flow')
set_param('ex_ext_ctrl_alg/Temp Setpt','Value','PARAM_setpoint_temp')

clear temp PARAM_setpoint_flow PARAM_setpoint_temp mdlwks portHandles outportHandle

Сконфигурируйте внутренние данные

Во внешнем коде внутренние данные, которые не участвуют в интерфейсах модуля, таких как данные состояния и локальные переменные в функциях, соответствуют схемам именования. В модели сконфигурируйте внутренние данные, которые, кажется, в сгенерированном коде подражают этим схемам именования.

В диалоговом окне модели Configuration Parameters осмотрите Генерацию кода> панель Символов. Когда вы задаете значения для схем именования под управлением форматом Идентификатора:

  • $R представляет имя модели, ex_ext_ctrl_alg.

  • $N представляет имя каждого элемента модели, к которому схема применяется, такие как сигнал, состояние блока или стандартная структура данных.

  • $M представляет искажающий имя текст, который генератор кода вставляет, при необходимости, чтобы избежать столкновений имени. Для большинства правил именования требуется эта лексема.

Установите Глобальные переменные на $R$N_data$M. Эта установка управляет именами глобальных переменных, такими как те, которые представляют данные состояния. $R$N_data_$M схемы именования наиболее тесно аппроксимирует схему, которую используют переменные состояния во внешнем коде.

Установите Локальные временные переменные и Локальные выходные переменные блока к $N_local$M.

Также, чтобы установить параметры конфигурации, в командной строке, используют эти команды.

set_param('ex_ext_ctrl_alg','CustomSymbolStrGlobalVar','$R$N_data$M')
set_param('ex_ext_ctrl_alg','CustomSymbolStrTmpVar','$N_local$M')
set_param('ex_ext_ctrl_alg','CustomSymbolStrBlkIO','$N_local$M')

Сконфигурируйте данные состояния в модели, чтобы появиться в сгенерированном коде как отдельные глобальные переменные вместо полей стандартной структуры DWork. В модели выберите Code> C/C ++ Code> Configure Model in Code Perspective.

Под блок-схемой при Отображениях Кода> Значения по умолчанию Данных, для Внутренней строки данных, в столбце Класса памяти выбирают ExportedGlobal.

Также, чтобы сконфигурировать этот класс памяти по умолчанию, используйте эти команды в командной строке:

coder.mapping.create('ex_ext_ctrl_alg');
coder.mapping.defaults.set('ex_ext_ctrl_alg','InternalData',...
    'StorageClass','ExportedGlobal');

Сконфигурируйте организацию кода в каждом сгенерированном файле

Установите свою текущую папку на папку ex_ext_ctrl_alg.

cd(fullfile('..','ex_ext_ctrl_alg'))

В командной строке перейдите к папке, которая содержит встроенный шаблон ert_code_template.cgt генерации кода. По умолчанию, когда вы генерируете код с системным конечным файлом ert.tlc, этот шаблон управляет организацией и, частично, внешний вид кода в каждом сгенерированном файле.

currentFolder = pwd;
cd(fullfile(matlabroot,'toolbox','rtw','targets','ecoder'))

Скопируйте файл ert_code_template.cgt в свой буфер обмена.

Возвратитесь к папке ex_ext_ctrl_alg. Чтобы постараться не перезаписывать ваш буфер обмена, вместо того, чтобы использовать командную строку, чтобы перейти к папке, можно использовать Кнопку "Назад" в MATLAB.

cd(currentFolder)
clear currentFolder

Вставьте файл в папку ex_ext_ctrl_alg. Переименуйте файл как ex_my_code_template.cgt.

Откройте файл и замените содержимое на этот код.

type(fullfile(matlabroot,'examples','ecoder','ex_my_code_template.cgt'))

Этот новый шаблон соответствует более тесно организации внешних файлов. Например, шаблон организует подобные построения кода в именованные разделы (разграниченный комментариями) и, наверху шаблона, указывает только минимальную информацию о каждом сгенерированном файле.

В модели выберите Configuration Parameters> Code Generation> Templates.

Под шаблонами Кода и шаблонами Данных, набор эти четыре параметра конфигурации к ex_my_code_template.cgt.

Также, чтобы скопировать файл и установить параметры, в командной строке, используют эти команды.

copyfile(fullfile(matlabroot,'examples','ecoder','ex_my_code_template.cgt'),...
    'ex_my_code_template.cgt','f')
set_param('ex_ext_ctrl_alg','ERTSrcFileBannerTemplate','ex_my_code_template.cgt')
set_param('ex_ext_ctrl_alg','ERTHdrFileBannerTemplate','ex_my_code_template.cgt')
set_param('ex_ext_ctrl_alg','ERTDataSrcFileTemplate','ex_my_code_template.cgt')
set_param('ex_ext_ctrl_alg','ERTDataHdrFileTemplate','ex_my_code_template.cgt')

Сгенерируйте и осмотрите код

Поскольку внешний код уже задает функцию main, выберите Configuration Parameters> код Generate только и очиститесь, Параметры конфигурации> Генерируют пример основная программа.

set_param('ex_ext_ctrl_alg','GenCodeOnly','on')
set_param('ex_ext_ctrl_alg','GenerateSampleERTMain','off')

Сгенерируйте код из модели.

rtwbuild('ex_ext_ctrl_alg')

В отчете генерации кода осмотрите сгенерированные файлы. Код удовлетворяет требования. Например, ex_ext_ctrl_sigs.c задает выходные сигналы управления, CONTR_SIG_FLOW и CONTR_SIG_TEMP.

file = fullfile('ex_ext_ctrl_alg_ert_rtw','ex_ext_ctrl_sigs.c');
rtwdemodbtype(file,'dataPath_flow_T CONTR_SIG_FLOW;',...
    'dataPath_temp_T CONTR_SIG_TEMP;',1,1)

Параметры заданного значения появляются в ex_ext_ctrl_params.c.

file = fullfile('ex_ext_ctrl_alg_ert_rtw','ex_ext_ctrl_params.c');
rtwdemodbtype(file,'const dataPath_flow_T PARAM_setpoint_flow = 3.0;',...
    'const dataPath_temp_T PARAM_setpoint_temp = 2.0;',1,1)

Файл ex_ext_ctrl_alg.c задает глобальные переменные, чтобы хранить данные состояния. Переменные следуют схеме именования, которую вы задали. Код подобен следующему:

dataPath_temp_T ex_ext__Integrator_DSTATE_datag;
dataPath_flow_T ex_ext_c_Integrator_DSTATE_data;
dataPath_temp_T ex_ext_ctrl_Filter_DSTATE_datad;
dataPath_flow_T ex_ext_ctrl__Filter_DSTATE_data;

В том же файле образцовая функция выполнения, ex_ext_ctrl_alg_step, создает переменные локальной функции, чтобы сохранить временные вычисления. Переменные следуют схеме именования, которую вы задали. Код подобен следующему:

dataPath_flow_T Diff_local;
dataPath_flow_T FilterCoefficient_local;
dataPath_temp_T Diff1_local;
dataPath_temp_T FilterCoefficient_locali;

Некоторые имена глобальной и локальной переменной содержат дополнительные символы искажения, которые предотвращают столкновения имени. Эти дополнительные символы соответствуют лексеме $M, которую вы задали в схемах именования.

Файлы сгенерированного кода находятся в сгенерированных папках ex_ext_ctrl_alg_ert_rtw и slprj. Вы должны системы управления файла конфигурации и инструменты сборки, чтобы использовать эти папки и файлы.

Похожие темы