Программирование MATLAB для генерации кода

В этом примере показан рекомендуемый рабочий процесс для генерации автономного исполняемого файла из кода MATLAB ®, который содержит интерфейсы ROS.

Необходимые условия

  • Этот пример требует MATLAB Coder™.

  • Вы должны иметь доступ к компилятору C/C + +, который настроен правильно. Можно использовать mex -setup cpp чтобы просмотреть и изменить компилятор по умолчанию. Для получения дополнительной информации см. раздел «Изменение компилятора по умолчанию».

Обзор

Подмножество функций ROS MATLAB, таких как rossubscriber, rospublisher, и rosrate поддержка генерации кода С++. Чтобы создать автономный узел ROS из кода MATLAB, выполните следующие шаги:

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

  • Добавьте %#codegen директива на функцию MATLAB, чтобы указать, что она предназначена для генерации кода. Эта директива также позволяет анализатору кода MATLAB идентифицировать предупреждения и ошибки, характерные для MATLAB для генерации кода.

  • Измените функции ROS, чтобы использовать структуры сообщений.

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

  • Создайте объект строения MATLAB Coder и укажите оборудование следующим 'Robot Operating System (ROS)'.

  • Использование codegen команда для генерации независимого исполняемого файла.

Сгенерируйте код для абонента

Примите во внимание следующий код MATLAB.

function mynode(numIterations)
%mynode Receive and display sensor_msgs/JointState messages
rosinit;

% Trajectory points to be published
sub = rossubscriber("/servo");

% Display position 
for k = 1:numIterations
    msg = receive(sub);
    if ~isempty(msg.Position > 0)
        disp(msg.Position(1))
    else
        disp("Received empty message..");
    end
end
rosshutdown;
end

Этот код MATLAB получает sensor_msgs/JointState сообщения, опубликованные в /servo topic и отображает первый элемент положения в цикле. Функция имеет входной параметр, которая устанавливает количество итераций. Чтобы создать отдельный узел ROS, измените код следующим образом:

  • Устраните входной параметр numIterations использование while цикл.

  • Добавьте %#codegen директива.

  • Укажите тип сообщения для rossubscriber вызов.

  • Вместо классов сообщений используйте структуры сообщений.

  • Устранение rosinit и rosshutdown вызовы, которые не генерируют код.

  • Замените disp функция, которая не поддерживает генерацию кода, с fprintf.

Обратите внимание, что функции rosinit и rosshutdown выполняются только один раз в сеансе работы с MATLAB. Избегайте rosinit и rosshutdown функции для кода, предназначенного для автономного развертывания. В автономном развертывании отдельные узлы ROS не должны запускать или останавливать хозяин ROS. Если вам нужно включить rosinit и roshutdown вызовы в коде MATLAB для интерпретируемого выполнения, объявите их как внешние функции в верхней части функции точки входа.

Функция точки входа не может принимать какие-либо входы или выходы возврата. Автономный исполняемый файл узла ROS предназначен для запуска вне MATLAB, например, с системного командного терминала, и поэтому не может принимать какие-либо входы MATLAB или возвращать выходы MATLAB.

Чтобы исключить входной параметр numIterations, замените for цикл с бесконечным while цикл. Для автономного развертывания ожидается, что сгенерированный узел будет запускаться до тех пор, пока вы не закроете его на стороне. Хорошей методикой программирования является замена for циклы с while цикл для автономного развертывания.

The rossubscriber Для генерации кода функции требуется, чтобы тип сообщения был задан как временная константа компиляции. Функция использует эту информацию для создания возврата типа сообщения для receive вызовы. The rossubscriber функция поддерживает генерацию кода только для структур сообщений. Чтобы вернуть структуру сообщения, задайте аргумент пары "имя-значение", "DataFormat","struct", при создании абонента.

После изменения кода код MATLAB для функции точки входа следующий:

function mynode
%mynode Receive and display sensor_msgs/JointState messages
%#codegen

% Trajectory points to publish
sub = rossubscriber("/servo","sensor_msgs/JointState","DataFormat","struct");

% Display position 
while (1) 
    msg = receive(sub);
    if ~isempty(msg.Position > 0)
        fprintf("Position = %f\n",msg.Position(1))
    else
        fprintf("Received empty message..\n");
    end
end
end

Создайте строение MATLAB Coder, которая использует "Robot Operating System (ROS)" оборудование. Установите HardwareImplementation.ProdHWDeviceType параметр объекта строения MATLAB Coder для предполагаемого оборудования развертывания. Например, если вы развертываете сгенерированный код на наборе компьютеров Windows HardwareImplementation.ProdHWDeviceType на "Intel->x86-64 (Windows64)". Чтобы сгенерировать код, выполните следующие команды:

cfg = coder.config("exe");
cfg.Hardware = coder.hardware("Robot Operating System (ROS)");
cfg.Hardware.DeployTo = "Localhost"; 
cfg.Hardware.BuildAction = "Build and run";
cfg.HardwareImplementation.ProdHWDeviceType = "Intel->x86-64 (Windows64)";
cfg.HardwareImplementation.ProdLongLongMode = true; % Use 'long long' for Int64 or Uint64 data types
codegen mynode -config cfg

Вы можете отправлять сообщения в mynode с помощью следующей команды на терминале ROS:

rostopic pub /servo sensor_msgs/JointState -r 1 "{header:{seq: 0, stamp:{secs: 0,nsecs: 0},frame_id:""},name:["joint"],position:[150.0,100.0],velocity:[0.0,0.0],effort:[0,0]}"

Сгенерируйте код для издателя

Примите во внимание следующий код MATLAB.

function mypubnode(updateRate)
%mypubnode Publish joint trajectory messages

% Create publisher 
pub = rospublisher("/traj","trajectory_msgs/JointTrajectory");

% Create a message 
msg = rosmessage("trajectory_msgs/JointTrajectory");
msg.JointNames{1} = 'Left';
msg.JointNames{2} = 'Right';
trajMsg = rosmessage("trajectory_msgs/JointTrajectoryPoint");
r = rosrate(updateRate);
while (1)
    msg.Header.Stamp = rostime("now");
    x = rand;
    y = rand;
    trajMsg.Positions = [x y -x -y];
    msg.Points = [trajMsg trajMsg];
    send(pub,msg);
    waitfor(r);
end
end

Этот код MATLAB публикует trajectory_msgs/JointTrajectory сообщения в /traj тема. Частоту публикации сообщений можно установить внешне. The trajectory_msgs/JointTrajectory сообщение является вложенным сообщением, которое имеет следующие подполя:

>> rosmsg show trajectory_msgs/JointTrajectory
std_msgs/Header Header
char[] JointNames
JointTrajectoryPoint[] Points

Сообщение может содержать несколько соединений и несколько точек траектории. Если количество соединений M, и количество точек траектории для каждого соединения N, trajMsg имеет размерности M-by-1 и trajMsg.Positions имеет размерности N-by-1. В данном примере публикуйте две точки траектории на соединение.

Функция имеет входной параметр, которая устанавливает количество итераций. Чтобы создать отдельный узел ROS, измените код следующим образом:

  • Устраните входной параметр updateRate путем непосредственного определения его в теле функции.

  • Добавьте %#codegen директива.

  • Вместо классов сообщений используйте структуры сообщений.

  • Удалите все поля сообщений, которые используют строки камер для подготовки к генерации кода.

  • Вырастите поля структуры сообщений переменного размера в правильной размерности.

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

Измените rospublisher, rosmessage и rosrate функций для использования структур сообщений. The trajectory_msgs/JointTrajectory структура сообщения имеет поле, JointNames, который относится к строке камер типа. Поля сообщений этого типа не поддерживаются для генерации кода из-за ограничений MATLAB Coder. Для порядка кода для mypubnode функции, избегайте использования JointNames поля в генерации кода с помощью функции coder.targe.

Исходный mypubnode функция увеличивает поля переменного размера структур сообщений в неправильной размерности. Как рисунок, создайте сообщение типа trajectory_msgs/JointTrajectory в командной строке MATLAB. Обратите внимание, что первая размерность полей переменного размера имеет размер 0, а второе измерение имеет размер 1:

msg = rosmessage('trajectory_msgs/JointTrajectory')

msg = 

  ROS JointTrajectory message with properties:

    MessageType: 'trajectory_msgs/JointTrajectory'
         Header: [1×1 Header]
         Points: [0×1 JointTrajectoryPoint]
     JointNames: {0×1 cell}

  Use showdetails to show the contents of the message

Поля с размерностями 0 на 1 растут в первом измерении. Оригинальный код увеличивает Points и Positions поля во втором измерении, которое работает в интерпретированном режиме, но не поддерживается для генерации кода. При попытке увеличить поля переменного размера структуры сообщения в неправильной размерности появляется следующее сообщение об ошибке:

??? This assignment writes a 'trajectory_msgs_JointTrajectoryPointStruct_T' value into a 'struct_T' type. Code generation
does not support changing types through assignment. Check preceding assignments or input type specifications for type
mismatches.

После изменения кода код MATLAB для функции точки входа следующий:

function mypubnode
%mypubnode Publish joint trajectory messages
%#codegen

% Create publisher 
pub = rospublisher("/traj","trajectory_msgs/JointTrajectory","DataFormat","struct");

% Create a msg 
msg = rosmessage("trajectory_msgs/JointTrajectory","DataFormat","struct");
if isempty(coder.target)
    msg.JointNames{1} = 'Left';
    msg.JointNames{2} = 'Right';
end
trajMsg = rosmessage("trajectory_msgs/JointTrajectoryPoint","DataFormat","struct");
r = rosrate(1);
while (1)
    msg.Header.Stamp = rostime("now","DataFormat","struct");
    x = rand;
    y = rand;
    trajMsg.Positions = [x; y; -x; -y]; % Grow variable-size fields in the correct dimension
    msg.Points = [trajMsg; trajMsg];    % Grow variable-size fields in the correct dimension
    send(pub,msg);
    waitfor(r);
end
end

Создайте строение MATLAB Coder, которая использует "Robot Operating System (ROS)" оборудование. Установите HardwareImplementation.ProdHWDeviceType параметр объекта строения MATLAB Coder для предполагаемого оборудования развертывания. Например, если вы развертываете сгенерированный код на наборе компьютеров Windows HardwareImplementation.ProdHWDeviceType на "Intel->x86-64 (Windows64)". Чтобы сгенерировать код, выполните следующие команды:

cfg = coder.config("exe");
cfg.Hardware = coder.hardware("Robot Operating System (ROS)");
cfg.Hardware.DeployTo = "Localhost";
cfg.Hardware.BuildAction = "Build and run";
cfg.HardwareImplementation.ProdHWDeviceType = "Intel->x86-64 (Windows64)";
cfg.HardwareImplementation.ProdLongLongMode = true; % Use 'long long' for Int64 or Uint64 data types
codegen mypubnode -config cfg

Вы можете изучить содержимое сообщений, опубликованных mypubnode использование rostopic echo /traj команда на терминале ROS.