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

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

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

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

Скопируйте скрипт 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 модель, на вкладке Modeling, нажимает 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. Включите перспективу Кода. В галерее Apps нажмите Embedded Coder.

Под блок-схемой при Отображениях Кода> Значения по умолчанию Данных, для Внутренней строки данных, в столбце Класса памяти выбирают 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. Вы должны системы управления файла конфигурации и инструменты сборки, чтобы использовать эти папки и файлы.

Похожие темы