Ros Ug
Ros Ug
User's Guide
R2023b
How to Contact MathWorks
Phone: 508-647-7000
iii
Generate ROS Node for UAV Waypoint Follower . . . . . . . . . . . . . . . . . . . 1-182
Build and Deploy Visual SLAM Algorithm with ROS in MATLAB . . . . . 1-277
iv Contents
Using ROS Bridge to Establish Communication Between ROS and ROS 2
......................................................... 2-55
ROS Topics
3
ROS Network Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2
Network Connection Layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2
v
Limitations of ROS Messages in MATLAB . . . . . . . . . . . . . . . . . . . . . . . . . 3-5
ROS Data Type Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-6
Supported Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-6
vi Contents
Playback Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-63
Deploy ROS Node for Sign Following Robot with Time Synchronization
Using Simulink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-64
ROS 2 Topics
4
ROS 2 Custom Message Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Custom Message Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Custom Message Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Custom Message Creation Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-3
vii
ROS Model Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-5
Enable ROS Time Model Stepping for Deployed ROS Nodes . . . . . . . . . . 6-37
viii Contents
Log ROS Messages from Simulink to a Rosbag Logfile . . . . . . . . . . . . . . 6-63
Use ROS Logger App to Save ROS Messages from Simulink . . . . . . . . . . 6-66
Use ROS 2 Logger App to Save ROS 2 Messages from Simulink . . . . . . . . 7-5
ix
ROS CUDA Simulink Topics
8
Lane and Vehicle Detection in ROS Using YOLO v2 Deep Learning
Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-2
x Contents
1
• “Sign Following Robot with Time Synchronization Using ROS and Gazebo Co-Simulation”
on page 1-3
• “Pick-and-Place Workflow in Unity 3D Using ROS” on page 1-9
• “Get Started with ROS” on page 1-40
• “Connect to a ROS Network” on page 1-45
• “Access the ROS Parameter Server” on page 1-50
• “Work with Basic ROS Messages” on page 1-53
• “Exchange Data with ROS Publishers and Subscribers” on page 1-60
• “Improve Performance of ROS Using Message Structures” on page 1-66
• “Call and Provide ROS Services” on page 1-75
• “Work with rosbag Logfiles” on page 1-80
• “Access the tf Transformation Tree in ROS” on page 1-86
• “Work with Specialized ROS Messages” on page 1-94
• “Work with Velodyne ROS Messages” on page 1-116
• “Get Started with a Real TurtleBot” on page 1-119
• “Get Started with ROS in Simulink” on page 1-127
• “Work with ROS Messages in Simulink” on page 1-136
• “Connect to a ROS-enabled Robot from Simulink” on page 1-142
• “Feedback Control of a ROS-Enabled Robot” on page 1-148
• “Fusion of Radar and Lidar Data Using ROS” on page 1-151
• “MATLAB Programming for Code Generation” on page 1-157
• “Generate a Standalone ROS Node” on page 1-163
• “Generate ROS Node for UAV Waypoint Follower” on page 1-182
• “Generate a Standalone ROS Node from Simulink” on page 1-194
• “Get Started with Gazebo and Simulated TurtleBot” on page 1-205
• “Add, Build, and Remove Objects in Gazebo” on page 1-213
• “Apply Forces and Torques in Gazebo” on page 1-220
• “Test Robot Autonomy in Simulation” on page 1-230
• “Set Up and Connect to CARLA Simulator” on page 1-235
• “Set Up and Connect to Unity Game Engine” on page 1-238
• “Communicate with the TurtleBot” on page 1-243
• “Explore Basic Behavior of the TurtleBot” on page 1-248
• “Control the TurtleBot with Teleoperation” on page 1-254
• “Obstacle Avoidance with TurtleBot and VFH” on page 1-259
• “Track and Follow an Object” on page 1-261
1 ROS Featured Examples
• “Build a Map Using Lidar SLAM with ROS in MATLAB” on page 1-270
• “Build and Deploy Visual SLAM Algorithm with ROS in MATLAB” on page 1-277
1-2
Sign Following Robot with Time Synchronization Using ROS and Gazebo Co-Simulation
This example shows how to use Simulink® to enable synchronized simulation between ROS and the
Gazebo robot simulator using the Gazebo Pacer (Robotics System Toolbox) block.
This example builds upon the “Sign-Following Robot with ROS in Simulink” on page 2-109 example,
which does not support synchronized simulation. Unsynchronized simulation can result in sensor data
loss or delayed messages and simulation time mismatch. Gazebo Co-Simulation is ROS-independent,
which enables it to synchronize the simulation times between Gazebo and Simulink when using the
Gazebo Pacer block. For more details about Gazebo Co-Simulation, see “Gazebo Simulation for
Robotics System Toolbox” (Robotics System Toolbox).
1 Download and install the virtual machine with ROS and Gazebo. See Setup Gazebo Simulation
Environment in “Perform Co-Simulation between Simulink and Gazebo” (Robotics System
Toolbox).
2 Start the Ubuntu® virtual machine (VM) desktop.
3 On the Ubuntu desktop, click Gazebo Sign Follower ROS Co-Sim to start the Gazebo world
built for this example.
The Simulink model used in this example is based on the Simulink model used in the “Sign-Following
Robot with ROS in Simulink” on page 2-109 example, with the addition of the Gazebo Pacer block.
open_system("signFollowingRobotROSCoSim.slx")
1-3
1 ROS Featured Examples
You can add the Gazebo Pacer block to an existing ROS–Gazebo Simulink model, as shown in the
model diagram, to enable synchronized simulation.
Before simulating the model, configure Gazebo Co-Simulation using the Gazebo Pacer block.
open_system("signFollowingRobotROSCoSim/Gazebo Pacer")
To configure the connection to the Gazebo simulation, click Configure Gazebo network and
simulation settings.
1-4
Sign Following Robot with Time Synchronization Using ROS and Gazebo Co-Simulation
1 From the Simulation tab, in the Prepare group, select ROS Network.
2 Specify the IP address and port number of the ROS master in Gazebo. For this example, the ROS
master in Gazebo is 192.168.145.143:11311. Set Hostname/IP Address to
192.168.145.143 and Port to 11311.
3 Click OK to apply your changes.
1-5
1 ROS Featured Examples
Run Model
Run the model and observe this simulation behavior, in addition to the behavior of the robot in the
robot simulator from the “Sign-Following Robot with ROS in Simulink” on page 2-109 example.
1-6
Sign Following Robot with Time Synchronization Using ROS and Gazebo Co-Simulation
1-7
1 ROS Featured Examples
• In the VM for your ROS–Gazebo co-simulation, locate the Gazebo plugin required for synchronized
simulation in /home/user/src/GazeboPlugin.
• To rebuild or replace the plugin, follow the Gazebo plugin manual installation steps in “Perform
Co-Simulation between Simulink and Gazebo” (Robotics System Toolbox).
• The code snippet of the updated world file shows the Gazebo plugin tag.
1-8
Pick-and-Place Workflow in Unity 3D Using ROS
This example shows how to set up an end-to-end pick-and-place workflow for a robotic manipulator
like the Kinova® Gen3, and simulate the robot in the Unity® game engine.
Overview
This example identifies and places objects into a bin using a Kinova Gen3 manipulator. The example
uses tools from three toolboxes:
• “Plan and Execute Task- and Joint-Space Trajectories Using KINOVA Gen3 Manipulator” (Robotics
System Toolbox) — Shows how to generate and simulate interpolated joint trajectories to move
from an initial to a desired end-effector pose.
• “Pick-and-Place Workflow Using Stateflow for MATLAB” (Robotics System Toolbox) — Shows how
to set up an end-to-end pick-and-place workflow for a robotic manipulator like the Kinova Gen3.
• “Get Started with Gazebo and Simulated TurtleBot” on page 1-205 — Shows how to set up the
connection between MATLAB and Gazebo.
• “Pick-and-Place Workflow in Gazebo Using ROS” (Robotics System Toolbox) — Shows how to set
up an end-to-end pick-and-place workflow for a robotic manipulator like the Kinova Gen3, and
simulate the robot in the Gazebo physics simulator.
• “Model and Control a Manipulator Arm with Robotics and Simscape” (Robotics System Toolbox) —
Shows how to design robot algorithms in Simulink®, and then simulate the action in a test
environment using Simscape™.
1-9
1 ROS Featured Examples
Pick-and-Place Workflow
1-10
Pick-and-Place Workflow in Unity 3D Using ROS
1-11
1 ROS Featured Examples
• URDF Importer — To import the robot model from URDF files. Download this package as a ZIP
file from the URDF Importer GitHub repository. This example has been tested with URDF Importer
version 0.5.2.
• ROS TCP Connector — To connect Unity with the ROS server. Download this package as a ZIP
file from the ROS TCP Connector GitHub repository. This example has been tested with ROS TCP
Connector version 0.7.0.
1-12
Pick-and-Place Workflow in Unity 3D Using ROS
The Robot.zip file included with this example contains the URDF file of the Kinova Gen3 robot with
a custom gripper attached to it. The file also contains the relevant mesh files for the robot model.
1 Extract the contents of the Robot.zip file to the Assets folder in the Unity project directory.
2 Right-click the URDF file in the Project pane and select Import Robot from Selected URDF
file.
3 In the URDF Import Settings window, click Import URDF.
1-13
1 ROS Featured Examples
1-14
Pick-and-Place Workflow in Unity 3D Using ROS
Zoom into the scene to view the imported Kinova Gen3 robot model.
1-15
1 ROS Featured Examples
Add Floor
1 From the Unity menu, select GameObject > 3D Object > Plane. Unity Editor adds a plane to
the scene and lists it in the Hierarchy pane.
2 In the Hierarchy pane, right-click the plane object and select Rename. Rename it as Floor.
3 In the Inspector pane, under Transform, set the X, Y, and Z values of Position to 0.
1-16
Pick-and-Place Workflow in Unity 3D Using ROS
Add Table
1 From the Unity menu, select GameObject > 3D Object > Cube. Unity Editor adds a cube to the
scene and lists it in the Hierarchy pane.
2 In the Hierarchy pane, right-click the cube object and select Rename. Rename it as Table.
3 In the Inspector pane, under Transform, set the Y and Z values of Position to 0.25 and set Y
value of Scale to 0.5.
1-17
1 ROS Featured Examples
Add Box
1 From the Unity menu, select GameObject > 3D Object > Cube. Unity Editor adds a cube to the
scene and lists it in the Hierarchy pane.
2 In the Hierarchy pane, right-click the cube object and select Rename. Rename it as Box.
3 In the Inspector pane, under Transform, set the Y value of Position to 0.525 and Z value of
Position to 0.25.
4 Set the X, Y, and Z values of Scale to 0.05.
5 In the Inspector pane, under Mesh Renderer, change the Material property of the box to a
non-default color for ease of visualization.
6 Click Add Component and search for rigidbody.
7 Select the RigidBody component to add it to the Inspector pane.
8 In the Inspector pane, under RigidBody, set the value of Mass to 0.01. If Use Gravity is not
selected, select it.
1-18
Pick-and-Place Workflow in Unity 3D Using ROS
1-19
1 ROS Featured Examples
1-20
Pick-and-Place Workflow in Unity 3D Using ROS
You can repeat the steps in Add Box on page 1-18 and Add Tag to Box on page 1-19 to add more
objects for the robot to pick.
Adjust Camera
1-21
1 ROS Featured Examples
%For Unity
configReqUnity = rosmessage(obj.ROSinfo.UnityConfigClient);
configReqUnity.ModelName = "gen3";
configReqUnity.JointPositions = JConfig;
configRespUnity = call(obj.ROSinfo.UnityConfigClient,configReqUnity,"Timeout",3);
end
1-22
Pick-and-Place Workflow in Unity 3D Using ROS
1 In the Hierarchy pane, under the gen3 robot object, select base_link.
2 In the Inspector pane, under Articulation Body, select Immovable.
1-23
1 ROS Featured Examples
1 In the Hierarchy pane, under the gen3 robot object, select gripper_finger1_finger_tip_link.
2 In the Inspector pane, click Add Component and search for box collider.
3 Select the Box Collider component to add it to the Inspector pane.
4 Adjust the values of the Center and Size properties of the collision box to ensure that it aligns
with the gripper finger mesh.
5 Repeat the previous steps for gripper_finger2_finger_tip_link.
1-24
Pick-and-Place Workflow in Unity 3D Using ROS
1 From the menu, select Edit > Project Settings to launch the Project Settings window.
1-25
1 ROS Featured Examples
MATLAB needs to communicate with Unity in order to transmit and receive information regarding the
robot model. The execution of the pick-and-place workflow requires channels of communication
between MATLAB and Unity. To establish communication for these channels, use custom services and
a publisher.
This example includes the ROS custom service definition (.srv) files. You can find these files inside
the unity_robotics_demo_msgs folder. The Generate Unity Scripts for Custom Services on page 1-
27 section shows how to generate ROS messages from the custom service definition files in Unity.
The Generate Custom ROS Messages in MATLAB on page 1-33 section shows how to generate ROS
messages from the custom service definition files in MATLAB.
1-26
Pick-and-Place Workflow in Unity 3D Using ROS
The PNPScripts.zip file included with this example contains C# (.cs) scripts you can use to
establish communication between Unity and MATLAB. The Add ROS Service Scripts in Unity on page
1-31 section shows how to add the Unity ROS service scripts to the scene. For more examples of
implementing the Unity ROS service, see these Unity Scripts in the Unity Robotics Hub GitHub
repository.
You must build the ROS custom service definition files into C# scripts for use in Unity programming.
The ROS TCP Connector package provides a tool you can use to build messages and services.
1-27
1 ROS Featured Examples
1 Copy the unity_robotics_demo_msgs folder, which contains the ROS custom service
definition files, to the Unity project folder. For more information on the service definition files in
the unity_robotics_demo_msgs folder, see the ROS Custom Services and Publisher on page
1-26 section.
2 From the Unity menu bar, select Robotics > Generate ROS Messages, to launch the tool for
building custom services.
3 In the ROS Message Browser window, browse to the the unity_robotics_demo_msgs folder
inside the Unity project folder.
4 Click Build 4 srvs.
Unity generates C# service scripts from the ROS custom service definition files.
1-28
Pick-and-Place Workflow in Unity 3D Using ROS
1-29
1 ROS Featured Examples
1 Extract the Control_Msgs.zip file inside the Unity project folder. For more information on ROS
control messages, see control_msgs Github repository.
2 From the Unity menu bar, select Robotics > Generate ROS Messages, to launch the tool for
building these messages.
3 In the ROS Message Browser window, browse to the the control_msgs folder inside the Unity
project folder.
4 Build only these messages, named in the errors returned by Unity:
FollowJointTrajectoryGoal.msg, GripperCommand.msg, and JointTolerance.msg.
5 Click Build 3 msgs.
Unity generates C# message scripts from the control_msgs message definition files, which resolves
the errors.
1-30
Pick-and-Place Workflow in Unity 3D Using ROS
1 Extract the PNPScripts.zip file to the Assets folder in the Unity project directory. For more
information on the service scripts in the PNPScripts.zip file, see the ROS Custom Services
and Publisher on page 1-26 section.
2 From the Unity menu bar, select GameObject > Create Empty. Unity adds an empty
GameObject to the scene and lists it in the Hierarchy pane.
3 Rename the empty GameObject to PNPScriptsObject.
4 In the Project pane, select all of the C# script files in the PNPScripts folder.
5 Drag the files to PNPScriptsObject in the Hierarchy pane.
1-31
1 ROS Featured Examples
1-32
Pick-and-Place Workflow in Unity 3D Using ROS
This example uses a Stateflow chart to schedule the tasks of the pick-and-place workflow. Open the
chart to examine the contents and follow the state transitions during chart execution.
edit exampleHelperFlowChartPickPlaceROSUnity.sfx
The chart dictates how the manipulator interacts with the objects, or parts. It consists of basic
initialization steps, followed by two main sections:
For a high-level description of the pick-and-place steps, see “Pick-and-Place Workflow Using Stateflow
for MATLAB” (Robotics System Toolbox).
Trajectory Planning
Use trapveltraj (Robotics System Toolbox) and transformtraj (Robotics System Toolbox)
functions to generate simple task-space trajectories from an initial to a desired task configuration.
For more details on planning and executing trajectories, see “Plan and Execute Task- and Joint-Space
Trajectories Using KINOVA Gen3 Manipulator” (Robotics System Toolbox).
You must generate ROS custom messages in MATLAB from the custom service definition files inside
the unity_robotics_demo_msgs folder. For more information on these service definition files, see
the ROS Custom Services and Publisher on page 1-26 section.
Use the rosgenmsg function to generate the custom messages, and follow the instructions in the
dialog box to add the messages to the MATLAB path.
answer = questdlg("Are the Custom ROS messages generated for MATLAB?", ...
"Custom ROS messages for MATLAB","Yes","No", "No");
switch answer
case "Yes"
% Continue with pick and place
case "No"
% Run rosgenmsg to build custom ROS messages for MATLAB
rosgenmsg
end
answer = questdlg("Are the Custom ROS messages added to MATLAB path?", ...
1-33
1 ROS Featured Examples
switch answer
case "Yes"
% Continue with pick and place
case "Add path..."
% Add the custom ROS messages to the MATLAB path
customROSMsgPath = uigetdir("", "Select the install\m folder created by rosgenmsg");
addpath(customROSMsgPath)
savepath
clear classes
rehash toolboxcache
case "Add path from current directory"
customROSMsgPath = uigetdir(fullfile(pwd, "matlab_msg_gen_ros1"), "Select the install\m f
addpath(customROSMsgPath)
savepath
clear classes
rehash toolboxcache
end
Start the ROS master from MATLAB. Alternatively, you can connect Unity and MATLAB to a ROS
master running elsewhere.
A ROS TCP endpoint node can facilitate the communication between Unity and ROS for sending and
receiving messages.
helperConnectROSUnity;
From the Unity menu bar, select Robotics > ROS Settings, to open the tool to specify the IP
address of the machine running the ROS master in the MATLAB session. For a detailed guide on
setting up the ROS Connection, see The Unity Side.
1-34
Pick-and-Place Workflow in Unity 3D Using ROS
Click the play button in Unity to simulate the scene. The console displays any critical errors in your
setup. Address the errors before proceeding with the example.
Ensure the Unity scene is running and that the connection to MATLAB is functioning. When the Unity
sceneis playing, you should see an overlay on the Game pane. The blue and green arrows next to
ROS IP indicate that there is a connection between Unity and the ROS master.
1-35
1 ROS Featured Examples
Use a dialog to confirm the Unity is running. Click Yes in the dialog to begin the simulation.
answer = questdlg("Click the Play button in Unity. Select Yes once the connection is established.
"Run Unity Scene","Yes","No", "No");
switch answer
case "Yes"
% Continue with pick and place
case "No"
% Stop the pick and place job
coordinator.FlowChart.endPickPlace;
delete(coordinator.FlowChart)
delete(coordinator);
end
To check the connection status in MATLAB is functioning, run the following rostopic commands and
verify if MATLAB is receiving the Unity published ROS topic /my_gen3_unity/joint_states.
rostopic list
/my_gen3_unity/joint_states
/rosout
/tf
Header
Stamp
Sec : 0
1-36
Pick-and-Place Workflow in Unity 3D Using ROS
Nsec : 0
Seq : 1
FrameId : 1
Name : {1} shoulder_link {2} half_arm_1_link {3} half_arm_2_link {4} forearm_lin
Position : [3.84349641535664e-06, -5.377179604693083e-06, 5.302986664901255e-06, -1.0956663572
Velocity : [1.649751438306241e-05, -3.894936167378246e-05, 5.202663783397106e-05, 8.8292196362
Effort : []
---
This simulation uses a Kinova Gen3 manipulator with a Robotiq gripper attached. Load the robot
model from a .mat file as a rigidBodyTree (Robotics System Toolbox) object.
load("exampleHelperKINOVAGen3GripperROSUnity.mat");
Set the initial robot configuration. Initialize the coordinator, which handles the robot control, by
specifying the robot model, initial configuration, and end-effector name.
initialRobotJConfig = [3.5797 -0.6562 -1.2507 -0.7008 0.7303 -2.0500 -1.9053];
endEffectorFrame = "gripper";
coordinator = exampleHelperCoordinatorPickPlaceROSUnity(robot,initialRobotJConfig,endEffectorFram
In Unity, verify that the robot model has moved to the position specified by initialRobotJConfig.
Specify the home configuration and two poses for placing objects.
1-37
1 ROS Featured Examples
coordinator.HomeRobotTaskConfig = getTransform(robot,initialRobotJConfig,endEffectorFrame);
coordinator.PlacingPose{1} = trvec2tform([0.2 0.55 0.26])*axang2tform([0 0 1 pi/2])*axang2tform([
coordinator.PlacingPose{2} = trvec2tform([0.2 -0.55 0.26])*axang2tform([0 0 1 pi/2])*axang2tform(
Connect the coordinator to the Stateflow chart. Once started, the Stateflow chart is responsible for
continuously going through the states of detecting objects, picking them up, and placing them in the
correct staging area.
coordinator.FlowChart = exampleHelperFlowChartPickPlaceROSUnity("coordinator",coordinator);
Create a dialog box for starting the pick-and-place task execution. To begin the simulation, click Yes
in the dialog box.
answer = questdlg("Do you want to start the pick-and-place job now?", ...
"Start job","Yes","No", "No");
switch answer
case "Yes"
% Trigger event to start Pick and Place in the Stateflow Chart
coordinator.FlowChart.startPickPlace;
case "No"
coordinator.FlowChart.endPickPlace;
delete(coordinator.FlowChart)
delete(coordinator)
end
Observe the robot model in Unity, and check that it performs the pick-and-place actions.
1-38
Pick-and-Place Workflow in Unity 3D Using ROS
The Stateflow chart stops automatically after four failed attempts to detect new objects. To stop the
pick-and-place task prematurely, uncomment and execute these lines of code or select the command
window and press Ctrl+C.
% coordinator.FlowChart.endPickPlace;
% delete(coordinator.FlowChart)
% delete(coordinator)
The Unity scene shows the robot in the working area as it moves the objects to the desired location.
The robot continues working until all objects have been placed. When the detection step does not find
any more objects four times, the Stateflow chart ends.
if strcmp(answer,"Yes")
while coordinator.NumDetectionRuns < 4
% Wait for no objects to be detected.
end
end
Kill the ROS TCP endpoint node and shut down the ROS network.
helperKillTCPEndpointNode;
rosshutdown
1-39
1 ROS Featured Examples
This example introduces how to set up ROS within MATLAB®, and get information about ROS
network and ROS messages.
Robot Operating System (ROS) is a communication interface that enables different parts of a robot
system to discover each other, and send and receive data between them. MATLAB® supports ROS
with a library of functions that enables you to exchange data with ROS-enabled physical robots or
robot simulators such as Gazebo®.
ROS Terminology
• A ROS network comprises different parts of a robot system (such as a planner or a camera
interface) that communicate over ROS. The network can be distributed over several machines.
• A ROS master coordinates the different parts of a ROS network. It is identified by a Master URI
(Uniform Resource Identifier) that specifies the hostname or IP address of the machine where the
master is running.
• A ROS node contains a collection of related ROS capabilities (such as publishers, subscribers, and
services). A ROS network can have many ROS nodes.
• Publishers, subscribers, and services are different kinds of ROS entities that process data. They
exchange data using messages.
• A publisher sends messages to a specific topic (such as "odometry"), and subscribers to that topic
receive those messages. A single topic can be associated with multiple publishers and subscribers.
For more information, see “Robot Operating System (ROS)” and the Concepts section on the ROS
website.
Use rosinit to initialize ROS. By default, rosinit creates a ROS master in MATLAB and starts a
global node that is connected to the master. The global node is automatically used by other ROS
functions.
rosinit
Use rosnode list to see all nodes in the ROS network. Note that the only available node is the
global node created by rosinit.
rosnode list
/matlab_global_node_13423
exampleHelperROSCreateSampleNetwork
Use rosnode list again to see the three new nodes (node_1, node_2, and node_3).
1-40
Get Started with ROS
rosnode list
/matlab_global_node_13423
/node_1
/node_2
/node_3
The figure shows the current state of the ROS network. The MATLAB global node is disconnected
since it currently does not have any publishers, subscribers or services.
Topics
Use rostopic list to see available topics in the ROS network. There are four active topics: /
pose, /rosout, /scan and /tf. The default topics: rosout and tf are always present in the ROS
network. The other two topics were created as part of the sample network.
rostopic list
/pose
/rosout
/scan
/tf
Use rostopic info <topicname> to get specific information about a specific topic. The command
below shows that /node_1 publishes (sends messages to) the /pose topic, and /node_2 subscribes
(receives messages from) to that topic. See “Exchange Data with ROS Publishers and Subscribers” on
page 1-60 for more information.
1-41
1 ROS Featured Examples
Type: geometry_msgs/Twist
Publishers:
* /node_1 (http://ah-avijayar:52609/)
Subscribers:
* /node_2 (http://ah-avijayar:52614/)
Use rosnode info <nodename> to get information about a specific node. The command below
shows that node_1 publishes to /pose, /rosout and /tf topics, subscribes to the /scan topic and
provides services: /node_1/get_loggers and /node_1/set_logger_level. The default logging services:
get_loggers and set_logger_level are provided by all the nodes created in ROS network.
rosnode info /node_1
Node: [/node_1]
URI: [http://ah-avijayar:52609/]
Services (2 Active):
* /node_1/get_loggers
* /node_1/set_logger_level
Services
ROS services provide a mechanism for procedure calls across the ROS network. A service client
sends a request message to a service server, which processes the information in the request and
returns with a response message (see “Call and Provide ROS Services” on page 1-75).
Use rosservice list to see all available service servers in the ROS network. The command below
shows that two services (/add and /reply) are available along with the default logger services of all
the nodes.
rosservice list
/add
/matlab_global_node_13423/get_loggers
/matlab_global_node_13423/set_logger_level
/node_1/get_loggers
/node_1/set_logger_level
/node_2/get_loggers
/node_2/set_logger_level
/node_3/get_loggers
/node_3/set_logger_level
/reply
Node: /node_3
URI: rosrpc://ah-avijayar:52618
1-42
Get Started with ROS
Type: roscpp_tutorials/TwoInts
Args: MessageType A B
Messages
Publishers, subscribers, and services use ROS messages to exchange information. Each ROS message
has an associated message type that defines the datatypes and layout of information in that message
(See “Work with Basic ROS Messages” on page 1-53).
Use rostopic type <topicname> to see the message type used by a topic. The command below
shows that the /pose topic uses messages of type geometry_msgs/Twist.
geometry_msgs/Twist
Use rosmsg show <messagetype> to view the properties of a message type. The
geometry_msgs/Twist message type has two properties, Linear and Angular. Each property is a
message of type geometry_msgs/Vector3, which in turn has three properties of type double.
% This expresses velocity in free space broken into its Linear and Angular parts.
Vector3 Linear
Vector3 Angular
double X
double Y
double Z
Use rosmsg list to see the full list of message types available in MATLAB.
exampleHelperROSShutDownSampleNetwork
Use rosshutdown to shut down the ROS network in MATLAB. This shuts down the ROS master that
was started by rosinit and deletes the global node. Using rosshutdown is the recommended
procedure once you are done working with the ROS network.
rosshutdown
1-43
1 ROS Featured Examples
Next Steps
1-44
Connect to a ROS Network
A ROS network consists of a single ROS master and multiple ROS nodes. The ROS master facilitates
the communication in the ROS network by keeping track of all active ROS entities. Every node needs
to register with the ROS master to be able to communicate with the rest of the network. MATLAB®
can start the ROS master, or the master can be launched outside of MATLAB (for example, on a
different computer).
When you work with ROS, you typically follow these steps:
1 Connect to a ROS network. To connect to a ROS network, you can create the ROS master in
MATLAB or connect to an existing ROS master. In both cases, MATLAB will also create and
register its own ROS node (called the MATLAB global node) with the master. The rosinit
function manages this process.
2 Exchange data. Once connected, MATLAB exchanges data with other ROS nodes through
publishers, subscribers, and services.
3 Disconnect from the ROS network. Call the rosshutdown function to disconnect MATLAB from
the ROS network.
• To create the ROS master in MATLAB, call rosinit without any arguments. This function also
creates the global node, which MATLAB uses to communicate with other nodes in the ROS
network.
rosinit
ROS nodes that are external to MATLAB can now join the ROS network. They can connect to the ROS
master in MATLAB by using the hostname or IP address of the MATLAB host computer.
You can shut down the ROS master and the global node by calling rosshutdown.
rosshutdown
You can also use the rosinit command to connect to an external ROS master (for example running
on a robot or a virtual machine). You can specify the address of the master in two ways: by an IP
address or by hostname of the computer that runs the master.
1-45
1 ROS Featured Examples
After each call to rosinit, you have to call rosshutdown before calling rosinit with a different
syntax. For brevity, these calls to rosshutdown are omitted in these examples.
rosinit('192.168.1.1')
rosinit('master_host')
Both calls to rosinit assume that the master accepts network connections on port 11311, which is
the standard ROS master port. If the master is running on a different port, you can specify it as a
second argument. To connect to a ROS master running on host name master_host and port 12000,
use the following command:
rosinit('master_host',12000)
If you know the entire Uniform Resource Identifier (URI) of the master, you can create the global
node and connect to this master using this syntax:
rosinit('http://192.168.1.1:12000')
In some cases, your computer may be connected to multiple networks and have multiple IP
addresses. This illustration shows an example.
1-46
Connect to a ROS Network
The computer on the bottom left runs MATLAB and is connected to two different networks. In one
subnet, its IP address is 73.195.120.50, and in the other, its IP is 192.168.1.100. This computer
wants to connect to the ROS master on the TurtleBot® computer at IP address 192.168.1.1. As
part of the registration with the master, the MATLAB global node has to specify the IP address or host
name where other ROS nodes can reach it. All the nodes on the TurtleBot will use this address to
send data to the global node in MATLAB.
When rosinit is invoked with the master's IP address, it tries to detect the network interface used
to contact the master and use that as the IP address for the global node. If this automatic detection
fails, you can explicitly specify the IP address or host name by using the NodeHost name-value pair
in the rosinit call. The NodeHost name-value pair can be used with any of the other syntaxes
already shown.
These commands advertise your computer's IP address to the ROS network as 192.168.1.100.
rosinit('192.168.1.1','NodeHost','192.168.1.100')
rosinit('http://192.168.1.1:11311','NodeHost','192.168.1.100')
rosinit('master_host','NodeHost','192.168.1.100')
Once a node is registered in the ROS network, you can see the address that it advertises by using the
command rosnode info <nodename>. You can see the names of all registered nodes by calling
rosnode list.
1-47
1 ROS Featured Examples
In advanced use cases, you might want to specify the address of a ROS master and your advertised
node address through standard ROS environment variables. The syntaxes that were explained in the
previous sections should be sufficient for the majority of your use cases.
If no arguments are provided to rosinit, the function will also check the values of standard ROS
environment variables. These variables are ROS_MASTER_URI, ROS_HOSTNAME, and ROS_IP. You can
see their current values using the getenv command:
getenv('ROS_MASTER_URI')
getenv('ROS_HOSTNAME')
getenv('ROS_IP')
You can set these variables using the setenv command. After setting the environment variables, call
rosinit with no arguments. The address of the ROS master is specified by ROS_MASTER_URI, and
the global node's advertised address is given by ROS_IP or ROS_HOSTNAME. If you specify additional
arguments to rosinit, they override the values in the environment variables.
setenv('ROS_MASTER_URI','http://192.168.1.1:11311')
setenv('ROS_IP','192.168.1.100')
rosinit
You do not have to set both ROS_HOSTNAME and ROS_IP. If both are set, ROS_HOSTNAME takes
precedence.
Verify Connection
For your ROS connection to work correctly, you must ensure that all nodes can communicate with the
master and with each other. The individual nodes must communicate with the master to register
subscribers, publishers, and services. They must also be able to communicate with one another to
send and receive data. If your ROS network is not set up correctly, it is possible to be able to send
data and be unable to receive data (or vice versa).
This diagram shows a ROS Network with a single ROS master and two different nodes that register
themselves with the master. Each node contacts the master to find the advertised address of the
other node in the ROS network. Once each node knows the other node's address, a data exchange
can be established without involvement of the master.
1-48
Connect to a ROS Network
Next Steps
• See “Exchange Data with ROS Publishers and Subscribers” on page 1-60 to explore publishers
and subscribers in ROS.
See Also
Related Examples
• “Get Started with ROS in Simulink” on page 1-127
1-49
1 ROS Featured Examples
This example explores how to add and retrieve parameters on the ROS parameter server. The
parameter server usually runs on the same device that launches the ROS master. The parameters are
accessible globally over the ROS network and can be used to store static data such as configuration
parameters. Supported data types include strings, integers, doubles, logicals, and cell arrays.
Prerequisites: “Get Started with ROS” on page 1-40, “Connect to a ROS Network” on page 1-45
rosinit
Create a parameter tree object to interact with the parameter server. Use the parameter tree to
interact with the parameter server and call functions such as set, get, del, has and search. Create
a new parameter server using rosparam.
ptree = rosparam
ptree =
ParameterTree with properties:
To set a parameter for the robot IP address, use the parameter name ROBOT_IP. Check if a
parameter with the same name already exists. Use the has function.
has(ptree,'ROBOT_IP')
ans = logical
0
If has returns 0 (false) as the output, then the ROBOT_IP name could not be found on the parameter
server.
Add some parameters indicating a robot's IP address to the parameter server. Use the set function
for this purpose.
set(ptree,'ROBOT_IP','192.168.1.1');
set(ptree,'/myrobot/ROBOT_IP','192.168.1.100');
The ROBOT_IP parameters are now available to all nodes connected to this ROS master. You can
specify parameters within a namespace. For example, the /myrobot/ROBOT_IP parameter is within
the /myrobot namespace in this example.
1-50
Access the ROS Parameter Server
set(ptree,'MAX_SPEED',1.5);
Use a cell array as an input to the set function. Set a parameter that has the goal coordinates {x, y,
z} for the robot.
set(ptree,'goal',{5.0,2.0,0.0});
set(ptree,'/myrobot/ROBOT_NAME','TURTLE');
set(ptree,'/myrobot/MAX_SPEED',1.5);
set(ptree,'/newrobot/ROBOT_NAME','NEW_TURTLE');
Retrieve the robot's IP address from the ROBOT_IP parameter in the /myrobot namespace using the
get function:
robotIP = get(ptree,'/myrobot/ROBOT_IP')
robotIP =
'192.168.1.100'
To get the entire list of parameters stored on the parameter server, use dot notation to access the
AvailableParameters property. The list contains all the parameters that you added in previous
sections.
plist = ptree.AvailableParameters
You can also use the set function to change parameter values. Note that the modification of a
parameter is irreversible, since the parameter server will simply overwrite the parameter with the
new value. You can verify if a parameter already exists by using the has function.
set(ptree,'MAX_SPEED',1.0);
The modified value can have a different data type from a previously assigned value. For example, the
value of the MAX_SPEED parameter is currently of type double. Set a string value for the MAX_SPEED
parameter:
set(ptree,'MAX_SPEED','none');
1-51
1 ROS Featured Examples
Delete Parameters
Use the del function to delete a parameter from the parameter server.
del(ptree,'goal');
Check if the goal parameter has been deleted. Use the has function.
has(ptree,'goal')
ans = logical
0
The output is 0 (false), which means the parameter was deleted from the parameter server.
Search Parameters
Search for all the parameters that contain 'myrobot' using the search command:
results = search(ptree,'myrobot')
Shut down the ROS master and delete the global node.
rosshutdown
Next Steps
• For application examples, see the “Get Started with Gazebo and Simulated TurtleBot” on page 1-
205 or “Get Started with a Real TurtleBot” on page 1-119 examples.
See Also
Related Examples
• “ROS Parameters in Simulink” on page 6-12
1-52
Work with Basic ROS Messages
This example shows various ways to create, explore, and populate ROS messages in MATLAB®, that
are commonly encountered in robotics applications.
Messages are the primary container for exchanging data in ROS. Topics and services use messages to
carry data between nodes. (See “Exchange Data with ROS Publishers and Subscribers” on page 1-60
and “Call and Provide ROS Services” on page 1-75 for more information on topics and services)
Prerequisites: “Get Started with ROS” on page 1-40, “Connect to a ROS Network” on page 1-45
To identify its data structure, each message has a message type. For example, sensor data from a
laser scanner is typically sent in a message of type sensor_msgs/LaserScan. Each message type
identifies the data elements that are contained in a message. Every message type name is a
combination of a package name, followed by a forward slash /, and a type name:
rosinit
exampleHelperROSCreateSampleNetwork
There are various nodes on the network with a few topics and affiliated publishers and subscribers.
You can see the full list of available topics by calling rostopic list.
rostopic list
/pose
/rosout
/scan
/tf
1-53
1 ROS Featured Examples
If you want to know more about the type of data that is sent through the /scan topic, use the
rostopic info command to examine it. /scan has a message type of sensor_msgs/LaserScan.
Type: sensor_msgs/LaserScan
Publishers:
* /node_3 (http://bat6326win64:49546/)
Subscribers:
* /node_1 (http://bat6326win64:49533/)
* /node_2 (http://bat6326win64:49538/)
The command output also tells you which nodes are publishing and subscribing to the topic. To learn
about publishers and subscribers, see “Call and Provide ROS Services” on page 1-75.
To find out more about the topic's message type, create an empty message of the same type using the
rosmessage function. rosmessage supports tab completion for the message type. To complete
message type names, type the first few characters of the name you want to complete, and then press
the Tab key.
For better efficiency when creating messages or communicating, use messages in structure format.
scandata = rosmessage("sensor_msgs/LaserScan","DataFormat","struct")
The created message scandata has many properties associated with data typically received from a
laser scanner. For example, the minimum sensing distance is stored in the RangeMin field, and the
maximum sensing distance is in RangeMax.
To see a complete list of all message types available for topics and services, use rosmsg list.
ROS messages are structures, and the message data is stored in the fields of the structures. MATLAB
features convenient ways to find and explore the contents of messages.
• If you subscribe to the /pose topic, you can receive and examine the messages that are sent.
posesub = rossubscriber("/pose","DataFormat","struct")
posesub =
Subscriber with properties:
1-54
Work with Basic ROS Messages
TopicName: '/pose'
LatestMessage: []
MessageType: 'geometry_msgs/Twist'
BufferSize: 1
NewMessageFcn: []
DataFormat: 'struct'
Use receive to get data from the subscriber. Once a new message is received, the function will
return it and store it in the posedata variable (the second argument is a time-out in seconds).
posedata = receive(posesub,10)
The message has a type of geometry_msgs/Twist. There are two other fields in the message:
Linear and Angular. You can see the values of these message fields by accessing them directly:
posedata.Linear
posedata.Angular
Each of the values of these message fields is actually a message in itself. The message type for these
is geometry_msgs/Vector3. geometry_msgs/Twist is a composite message made up of two
geometry_msgs/Vector3 messages.
Data access for these nested messages works exactly the same as accessing the data in other
messages. Access the X component of the Linear message using this command:
xpos = posedata.Linear.X
xpos = 0.0457
If you want a quick summary of all the data contained in a message, call the rosShowDetails
function. rosShowDetails works on messages of any type and recursively displays all the message
data fields.
rosShowDetails(posedata)
ans =
'
1-55
1 ROS Featured Examples
MessageType : geometry_msgs/Twist
Linear
MessageType : geometry_msgs/Vector3
X : 0.04571669482429456
Y : -0.001462435127715878
Z : 0.03002804688888001
Angular
MessageType : geometry_msgs/Vector3
X : -0.03581136613727846
Y : -0.007823871737372501
Z : 0.04157355251890671'
rosShowDetails helps you during debugging and when you want to quickly explore the contents of
a message.
You can also set message field values. Create a message with type geometry_msgs/Twist.
twist = rosmessage("geometry_msgs/Twist","DataFormat","struct")
The numeric fields of this message are initialized to 0 by default. You can modify any of the properties
of this message. Set the Linear.Y entry equal to 5.
twist.Linear.Y = 5;
View the message data to make sure that your change took effect.
twist.Linear
Once a message is populated with your data, you can use it with publishers, subscribers, and
services. See the “Exchange Data with ROS Publishers and Subscribers” on page 1-60 and “Call and
Provide ROS Services” on page 1-75 examples.
You can save messages and store the contents for later use.
1-56
Work with Basic ROS Messages
Save the pose data to a MAT file using MATLAB's save function.
save('posedata.mat','posedata')
Before loading the file back into the workspace, clear the posedata variable.
clear posedata
Now you can load the message data by calling the load function. This loads the posedata from
above into the messageData structure. posedata is a data field of the struct.
messageData = load('posedata.mat')
messageData.posedata
delete('posedata.mat')
Arrays in Messages
Some messages from ROS are stored in or contain arrays of other messages.
tf
tf has two fields: MessageType contains a standard data array, and Transforms contains an object
array. There are 53 messages stored in Transforms, and all of them have the same structure.
tf.Transforms
1-57
1 ROS Featured Examples
ChildFrameId
Transform
Each object in Transforms has four properties. You can expand to see the Transform field of
Transforms.
tformFields = tf.Transforms.Transform
Note: The command output returns 53 individual answers, since each object is evaluated and returns
the value of its Transform field. This format is not always useful, so you can convert it to a cell array
with the following command:
cellTransforms = {tf.Transforms.Transform}
This puts all 53 object entries in a cell array, enabling you to access them with indexing.
In addition, you can access array elements the same way you access standard MATLAB vectors:
tf.Transforms(5)
Access the translation component of the fifth transform in the list of 53:
tf.Transforms(5).Transform.Translation
Remove the sample nodes, publishers, and subscribers from the ROS network.
exampleHelperROSShutDownSampleNetwork
Shut down the ROS master and delete the global node.
rosshutdown
Next Steps
• See “Work with Specialized ROS Messages” on page 1-94 for examples of handling images, point
clouds, and laser scan messages.
1-58
Work with Basic ROS Messages
• For application examples, see the “Get Started with Gazebo and Simulated TurtleBot” on page 1-
205 or “Get Started with a Real TurtleBot” on page 1-119 examples.
1-59
1 ROS Featured Examples
This example shows how to publish and subscribe to topics in a ROS network.
The primary mechanism for ROS nodes to exchange data is sending and receiving messages.
Messages are transmitted on a topic, and each topic has a unique name in the ROS network. If a node
wants to share information, it uses a publisher to send data to a topic. A node that wants to receive
that information uses a subscriber to that same topic. Besides its unique name, each topic also has a
message type, which determines the types of messages that are capable of being transmitted under
that topic.
• Topics are used for many-to-many communication. Many publishers can send messages to the
same topic and many subscribers can receive them.
• Publishers and subscribers are decoupled through topics and can be created and destroyed in any
order. A message can be published to a topic even if there are no active subscribers.
Besides how to publish and subscribe to topics in a ROS network, this example also shows how to:
Prerequisites: “Get Started with ROS” on page 1-40, “Connect to a ROS Network” on page 1-45
rosinit
1-60
Exchange Data with ROS Publishers and Subscribers
Create a sample ROS network with several publishers and subscribers using the provided helper
function exampleHelperROSCreateSampleNetwork.
exampleHelperROSCreateSampleNetwork
/pose
/rosout
/scan
/tf
Use rostopic info to check if any nodes are publishing to the /scan topic. The command below
shows that node_3 is publishing to it.
rostopic info /scan
Type: sensor_msgs/LaserScan
Publishers:
* /node_3 (http://ah-avijayar:62315/)
Subscribers:
* /node_1 (http://ah-avijayar:62305/)
* /node_2 (http://ah-avijayar:62310/)
Use rossubscriber to subscribe to the /scan topic. If the topic already exists in the ROS network
(as is the case here), rossubscriber detects its message type automatically, so you do not need to
specify it. Use messages in struct format for better efficiency.
laser = rossubscriber("/scan","DataFormat","struct");
pause(2)
Use receive to wait for a new message. (The second argument is a time-out in seconds.) The output
scandata contains the received message data.
scandata = receive(laser,10)
Some message types have visualizers associated with them. For the LaserScan message, rosPlot
plots the scan data. The MaximumRange name-value pair specifies the maximum plot range.
figure
rosPlot(scandata,"MaximumRange",7)
1-61
1 ROS Featured Examples
Instead of using receive to get data, you can specify a function to be called when a new message is
received. This allows other MATLAB code to execute while the subscriber is waiting for new
messages. Callbacks are essential if you want to use multiple subscribers.
robotpose = rossubscriber("/pose",@exampleHelperROSPoseCallback,"DataFormat","struct")
robotpose =
Subscriber with properties:
TopicName: '/pose'
LatestMessage: []
MessageType: 'geometry_msgs/Twist'
BufferSize: 1
NewMessageFcn: @exampleHelperROSPoseCallback
DataFormat: 'struct'
1-62
Exchange Data with ROS Publishers and Subscribers
One way of sharing data between your main workspace and the callback function is to use global
variables. Define two global variables pos and orient.
global pos
global orient
The global variables pos and orient are assigned in the exampleHelperROSPoseCallback
function when new message data is received on the /pose topic.
Wait for a few seconds to make sure that the subscriber can receive messages. The most current
position and orientation data will always be stored in the pos and orient variables.
pause(2)
pos
pos = 1×3
orient
orient = 1×3
If you type in pos and orient a few times in the command line, you can see that the values are
continuously updated.
Note: There are other ways to extract information from callback functions besides using globals. For
example, you can pass a handle object as additional argument to the callback function. See the
“Create Callbacks for Graphics Objects” documentation for more information about defining callback
functions.
Publish Messages
Create a publisher that sends ROS string messages to the /chatter topic (see “Work with Basic ROS
Messages” on page 1-53).
chatterpub = rospublisher("/chatter","std_msgs/String","DataFormat","struct")
chatterpub =
Publisher with properties:
TopicName: '/chatter'
NumSubscribers: 0
IsLatching: 1
MessageType: 'std_msgs/String'
DataFormat: 'struct'
1-63
1 ROS Featured Examples
chattermsg = rosmessage(chatterpub);
chattermsg.Data = 'hello world'
Use rostopic list to verify that the /chatter topic is available in the ROS network.
rostopic list
/chatter
/pose
/rosout
/scan
/tf
chattersub = rossubscriber("/chatter",@exampleHelperROSChatterCallback,"DataFormat","struct")
chattersub =
Subscriber with properties:
TopicName: '/chatter'
LatestMessage: []
MessageType: 'std_msgs/String'
BufferSize: 1
NewMessageFcn: @exampleHelperROSChatterCallback
DataFormat: 'struct'
Publish a message to the /chatter topic. The string is displayed by the subscriber callback.
send(chatterpub,chattermsg)
pause(2)
ans =
'hello world'
The exampleHelperROSChatterCallback function was called as soon as you published the string
message.
Remove the sample nodes, publishers, and subscribers from the ROS network. Clear the global
variables pos and orient.
exampleHelperROSShutDownSampleNetwork
clear global pos orient
Shut down the ROS master and delete the global node.
rosshutdown
1-64
Exchange Data with ROS Publishers and Subscribers
Next Steps
• To learn more about how ROS messages are handled in MATLAB, see “Work with Basic ROS
Messages” on page 1-53 and “Work with Specialized ROS Messages” on page 1-94.
• To explore ROS services, refer to “Call and Provide ROS Services” on page 1-75.
1-65
1 ROS Featured Examples
This example demonstrates the use of ROS message structures, and their benefits and differences
from message objects.
Message structures have better performance over objects when performing initial creation, reading
them from rosbag files, accessing nested properties, and performing communication operations over
the ROS network. Also, message structures are the only supported message format when generating
code through MATLAB Coder™.
ROS message objects are instances of classes defined specifically for each message type.
msgObj = rosmessage("nav_msgs/Path");
class(msgObj)
ans =
'ros.msggen.nav_msgs.Path'
The object properties contain the data of the message, and each object type has functions defined
that are specific to the ROS message.
showdetails(msgObj)
Header
Stamp
Sec : 0
Nsec : 0
Seq : 0
FrameId :
Poses
ROS message structures have been introduced to improve the performance of using ROS messages.
Each message is a MATLAB® structure data type with the same fields as the properties of the ROS
message objects.
msgStruct = rosmessage("nav_msgs/Path","DataFormat","struct")
class(msgStruct)
ans =
'struct'
To update existing code that uses objects, two common workflows are provided with the steps
required to update them.
1-66
Improve Performance of ROS Using Message Structures
Communication Workflow
This example code shows how to send and receive messages over the ROS network.
% Setup ROS network
rosinit
stringPub = rospublisher("/chatter","std_msgs/String");
stringSub = rossubscriber("/chatter","std_msgs/String");
How to Update
Set the data format name-value argument of the publisher and subscriber.
stringPub = rospublisher("/chatter","std_msgs/String","DataFormat","struct");
stringSub = rossubscriber("/chatter","std_msgs/String","DataFormat","struct");
Alternatively, the rosmessage object function for the publisher can be used. This syntax produces a
message that follows the format set in the publisher, and is the most efficient way to ensure
compatibility between the message and the publisher.
stringMsg = rosmessage(stringPub);
stringMsg.Data = 'Hello World!';
send(stringPub,stringMsg)
Because structures do not have object functions, new functions are provided to handle common ROS
message tasks. To show details a structure message, use the rosShowDetails function. To see all
the new functions provided, go to Message Handling Functions on page 1-68.
% Wait for message to be received and then check the value
pause(2)
rosShowDetails(stringSub.LatestMessage)
ans =
'
1-67
1 ROS Featured Examples
MessageType : std_msgs/String
Data : Hello World!'
For an example that reads messages from a rosbag, specify the DataFormat name-value argument
for the readMessages function and any publishers you use to send those messages.
Because functions on the ROS message objects are not usable with message structures, new
functions have been introduced for handling messages. This list includes functions for reading data
from or writing data to specialized messages.
1-68
Improve Performance of ROS Using Message Structures
Behavior Changes
An important consideration when converting code is that ROS message objects are handles, which
means that message objects are passed by reference when provided as inputs to functions. If a
message is modified within a function, the modification applies to the message in the MATLAB®
workspace as well.
msgObj = rosmessage("geometry_msgs/Pose2D");
pose = [1 2 3];
exampleHelperWritePoseToMsgObj(msgObj,pose)
disp(msgObj)
MessageType: 'geometry_msgs/Pose2D'
X: 1
Y: 2
Theta: 3
function exampleHelperWritePoseToMsgObj(pointMsg,pose)
pointMsg.X = pose(1);
pointMsg.Y = pose(2);
pointMsg.Theta = pose(3);
end
1-69
1 ROS Featured Examples
Message structures only pass their value when input into functions. If a message structure is
modified within a function, that modification will only apply to the structure within the scope of that
function. To make the modification available outside of the function, the message structure must be
returned.
msgStruct = rosmessage("geometry_msgs/Pose2D","DataFormat","struct");
pose = [1 2 3];
MessageType: 'geometry_msgs/Pose2D'
X: 0
Y: 0
Theta: 0
MessageType: 'geometry_msgs/Pose2D'
X: 1
Y: 2
Theta: 3
This applies to the specialized message handling functions as well. The write functions that update
message values now have output arguments to supply the updated message structure.
image = imread('imageMap.png');
% Message object
msg = rosmessage("sensor_msgs/Image");
msg.Encoding = 'rgb8';
writeImage(msg,image)
imshow(readImage(msg))
1-70
Improve Performance of ROS Using Message Structures
% Message structure
msg = rosmessage("sensor_msgs/Image","DataFormat","struct");
msg.Encoding = 'rgb8';
msg = rosWriteImage(msg,image);
imshow(rosReadImage(msg))
close
ROS time and duration message structures are unable to support operator overloading in the same
way that the time and duration objects do. Arithmetic and comparison operations should be done by
converting the time or duration structures to a numerical seconds value, performing the operation,
and then recreating the time or duration structure if necessary.
1-71
1 ROS Featured Examples
msg.Stamp = tNow;
% Message may be sent here
pause(1)
tNow = rostime("now","DataFormat","struct");
tNowSec = tNow.Sec + tNow.Nsec*1e-9;
end
With ROS message objects, data fields have specific types. When a data field value is set, the input is
converted to the correct type if possible. Otherwise, if conversion is not possible, an error is returned.
msg = rosmessage("std_msgs/Int8");
msg.Data = 20;
class(msg.Data)
ans =
'int8'
ROS message structures inherently accept any data type or field name without error.
msg = rosmessage("std_msgs/Int8","DataFormat","struct");
msg.Data = 'Test'
msg.Data = 20;
class(msg.Data)
ans =
'double'
Instead, invalid data types error when attempting to send the message over the ROS network.
pub = rospublisher("/int_topic","std_msgs/Int8","DataFormat","struct");
send(pub,msg)
Caused by:
Error using ros.internal.Node/publish
Field 'Data' is wrong type; expected a int8.
To prevent errors, ensure that messages are are using the correct data type from the message
definition.
int8 Data
Using message structures is a good first step to speed up the sending and retrieving of ROS
messages. Structures also improves the performance for setting and accessing data in nested
mesages.The following code demonstrates sending multiple messages with nested fields.
1-72
Improve Performance of ROS Using Message Structures
Reuse Messages
If messages are being created and modified in a loop, and the same data fields are being set each
iteration, it is faster to create the message only once. Move the creation of the messages outside the
loop, and reuse the same messages inside the loop for each iteration.
When reading or setting multiple fields in a nested message, extract the nested message before
reading or setting the fields.
1-73
1 ROS Featured Examples
end
send(pub,pathMsg)
end
For relatively large arrays of messages, preallocating a structure array can improve performance
when setting values in a loop. Use this method when the the array is a fixed length every iteration.
rosshutdown
See Also
Related Examples
• “Work with Specialized ROS Messages” on page 1-94
1-74
Call and Provide ROS Services
ROS supports two main communication mechanisms: topics and services. Topics have publishers and
subscribers and are used for sending and receiving messages (see “Exchange Data with ROS
Publishers and Subscribers” on page 1-60). Services, on the other hand, implement a tighter coupling
by allowing request-response communication. A service client sends a request message to a service
server and waits for a response. The server will use the data in the request to construct a response
message and sends it back to the client. Each service has a type that determines the structure of the
request and response messages. Services also have a name that is unique in the ROS network.
• A service request (or service call) is used for one-to-one communication. A single node will initiate
the request and only one node will receive the request and send back a response.
• A service client and a service server are tightly coupled when a service call is executed. The
server needs to exist at the time of the service call and once the request is sent, the client will
block until a response is received.
This example shows you how to set up service servers to advertise a service to the ROS network. In
addition, you will learn how to use service clients to call the server and receive a response.
Prerequisites: “Get Started with ROS” on page 1-40, “Connect to a ROS Network” on page 1-45,
“Exchange Data with ROS Publishers and Subscribers” on page 1-60
1-75
1 ROS Featured Examples
Before examining service concepts, start the ROS master in MATLAB® and the sample ROS network.
exampleHelperROSCreateSampleNetwork will create some service servers to simulate a realistic
ROS network.
rosinit
exampleHelperROSCreateSampleNetwork
Suppose you want to make a simple service server that displays "A service client is calling" when you
call the service. Create the service using the rossvcserver command. Specify the service name and
the service message type. Also define the callback function as exampleHelperROSEmptyCallback.
Callback functions for service servers have a very specific signature. For details, see the
documentation of rossvcserver.
testserver =
ServiceServer with properties:
ServiceType: 'std_srvs/Empty'
ServiceName: '/test'
NewRequestFcn: @exampleHelperROSEmptyCallback
DataFormat: 'struct'
You can see your new service, /test, when you list all services in the ROS network.
rosservice list
/add
/matlab_global_node_55791/get_loggers
/matlab_global_node_55791/set_logger_level
/node_1/get_loggers
/node_1/set_logger_level
/node_2/get_loggers
/node_2/set_logger_level
/node_3/get_loggers
/node_3/set_logger_level
/reply
/test
You can get more information about your service using rosservice info. The global node is listed
as node where the service server is reachable and you also see its std_srvs/Empty service type.
rosservice info /test
Node: /matlab_global_node_55791
URI: rosrpc://ah-csalzber:51639
Type: std_srvs/Empty
Args: MessageType
1-76
Call and Provide ROS Services
Use service clients to request information from a ROS service server. To create a client, use
rossvcclient with the service name as the argument.
Create a service client for the /test service that we just created.
testclient = rossvcclient("/test","DataFormat","struct")
testclient =
ServiceClient with properties:
ServiceType: 'std_srvs/Empty'
ServiceName: '/test'
DataFormat: 'struct'
Create an empty request message for the service. Use the rosmessage function and pass the client
as the first argument. This will create a service request function that has the message type and
format that is specified by the service.
testreq = rosmessage(testclient)
Ensure that the service is connected to the client, waiting for them to connect if necessary.
waitForServer(testclient,"Timeout",3)
When you want to get a response from the server, use the call function, which calls the service
server and returns a response. The service server you created before will return an empty response.
In addition, it will call the exampleHelperROSEmptyCallback function and displays the string "A
service client is calling". You can also define a Timeout parameter, which indicates how long the
client should wait for a response.
testresp = call(testclient,testreq,"Timeout",3);
If the call function above fails, it will error. Instead of an error, if you would prefer to react to a call
failure using conditionals, return the status and statustext outputs from the call function. The
status output indicates if the call succeeded, while statustext provides additional information.
Similar outputs can be returned from waitForServer.
numCallFailures = 0;
[testresp,status,statustext] = call(testclient,testreq,"Timeout",3);
if ~status
numCallFailures = numCallFailues + 1;
fprintf("Call failure number %d. Error cause: %s\n",numCallFailures,statustext)
else
disp(testresp)
end
MessageType: 'std_srvs/EmptyResponse'
1-77
1 ROS Featured Examples
Up to now, the service server has not done any meaningful work, but you can use services for
computations and data manipulation. Create a service that adds two integers.
There is an existing service type, roscpp_tutorials/TwoInts, that we can use for this task. You
can inspect the structure of the request and response messages by calling rosmsg show. The
request contains two integers, A and B, and the response contains their addition in Sum.
int64 A
int64 B
int64 Sum
Create the service server with this message type and a callback function that calculates the addition.
For your convenience, the exampleHelperROSSumCallback function already implements this
calculation. Specify the function as a callback.
sumserver = rossvcserver("/sum","roscpp_tutorials/TwoInts",@exampleHelperROSSumCallback,"DataForm
sumserver =
ServiceServer with properties:
ServiceType: 'roscpp_tutorials/TwoInts'
ServiceName: '/sum'
NewRequestFcn: @exampleHelperROSSumCallback
DataFormat: 'struct'
To call the service server, you have to create a service client. Note that this client can be created
anywhere in the ROS network. For the purposes of this example, we will create a client for the /sum
service in MATLAB.
sumclient = rossvcclient("/sum","DataFormat","struct")
sumclient =
ServiceClient with properties:
ServiceType: 'roscpp_tutorials/TwoInts'
ServiceName: '/sum'
DataFormat: 'struct'
Create the request message. You can define the two integers, A and B, which are added together
when you use the call command.
sumreq = rosmessage(sumclient);
sumreq.A = int64(2);
sumreq.B = int64(1)
1-78
Call and Provide ROS Services
B: 1
The expectation is that the sum of these two numbers will be 3. To call the service, use the following
command. The service response message will contain a Sum property, which stores the addition of A
and B. Ensure that the service server is available before making a call, and react appropriately if it is
not.
if isServerAvailable(sumclient)
sumresp = call(sumclient,sumreq,"Timeout",3)
else
error("Service server not available on network")
end
Remove the sample nodes and service servers from the ROS network.
exampleHelperROSShutDownSampleNetwork
Shut down the ROS master and delete the global node.
rosshutdown
Next Steps
• Refer to “Work with Basic ROS Messages” on page 1-53 to explore how ROS messages are
represented in MATLAB.
1-79
1 ROS Featured Examples
This example enables you to load a rosbag, and learn how to select and retrieve the contained
messages.
A rosbag or bag is a file format in ROS for storing message data. These bags are often created by
subscribing to one or more ROS topics, and storing the received message data in an efficient file
structure. MATLAB® can read these rosbag files and help with filtering and extracting message data.
See “ROS Log Files (rosbags)” on page 3-14 for more information about rosbag support in MATLAB.
Load a rosbag
bag = rosbag("ex_multiple_topics.bag")
bag =
BagSelection with properties:
The object returned from the rosbag call is a BagSelection object, which is a representation of all
the messages in the rosbag.
The object display shows details about how many messages are contained in the file (NumMessages)
and the time when the first (StartTime) and the last (EndTime) message were recorded.
Evaluate the AvailableTopics property to see more information about the topics and message
types that are recorded in the bag:
bag.AvailableTopics
ans=4×3 table
NumMessages MessageType
___________ ______________________ _____________________________
The AvailableTopics table contains the sorted list of topics that are included in the rosbag. The
table stores the number of messages, the message type, and the message definition for the topic. For
more information on the MATLAB table data type and what operations you can perform on it, see the
documentation for “Tables”.
1-80
Work with rosbag Logfiles
Initially the rosbag is only indexed by MATLAB and no actual message data is read.
You might want to filter and narrow the selection of messages as much as possible based on this
index before any messages are loaded into MATLAB memory.
Select Messages
Before you retrieve any message data, you must select a set of messages based on criteria such as
time stamp, topic name, and message type.
bag.MessageList
ans=36963×4 table
Time Topic MessageType FileOffset
______ ___________________ ______________________ __________
The MessageList table contains one row for each message in the bag (there are over 30,000 rows
for the bag in this example). The rows are sorted by time stamp in the first column, which represents
the time (in seconds) that the message was recorded.
Since the list is very large, you can also display a selection of rows with the familiar row and column
selection syntax:
bag.MessageList(500:505,:)
ans=6×4 table
Time Topic MessageType FileOffset
____ ___________________ ______________________ __________
1-81
1 ROS Featured Examples
Use the select function to narrow the selection of messages. The select function operates on the
bag object.
You can filter the message list by time, topic name, message type, or any combination of the three.
To select all messages that were published on the /odom topic, use the following select command:
bagselect1 = select(bag,"Topic","/odom")
bagselect1 =
BagSelection with properties:
Calls to the select function return another BagSelection object, which can be used to make
further selections or retrieve message data. All selection objects are independent of each other, so
you can clear them from the workspace once you are done.
You can make a different selection that combines two criteria. To get the list of messages that were
recorded within the first 30 seconds of the rosbag and published on the /odom topic, enter the
following command:
start = bag.StartTime
start = 201.3400
bagselect2 =
BagSelection with properties:
Use the last selection to narrow down the time window even further:
bagselect3 =
BagSelection with properties:
1-82
Work with rosbag Logfiles
The selection in this last step operated on the existing bagselect2 selection and returned a new
bagselect3 object.
If you want to save a set of selection options, store the selection elements in a cell array and then re-
use it later as an input to the select function:
selectOptions = {"Time",[start, start+1; start+5, start+6],"MessageType",["sensor_msgs/LaserScan"
bagselect4 = select(bag,selectOptions{:})
bagselect4 =
BagSelection with properties:
After you narrow your message selection, you might want to read the actual message data into
MATLAB. Depending on the size of your selection, this can take a long time and consume a lot of your
computer's memory. To improve time efficiency, read the messages from the rosbag in structure
format.
To retrieve the messages in you selection as a cell array, use the readMessages function:
msgs = readMessages(bagselect3,"DataFormat","struct");
size(msgs)
ans = 1×2
101 1
The resulting cell array contains as many elements as indicated in the NumMessages property of the
selection object.
In reading message data, you can also be more selective and only retrieve messages at specific
indices. Here is an example of retrieving 4 messages:
msgs = readMessages(bagselect3,[1 2 3 7],"DataFormat","struct")
msgs{2}
1-83
1 ROS Featured Examples
Each message in the cell array is a standard MATLAB ROS message structure. For more information
on messages, see the “Work with Basic ROS Messages” on page 1-53 example.
Sometimes you are not interested in the complete messages, but only in specific properties that are
common to all the messages in a selection. In this case, it is helpful to retrieve the message data as a
time series instead. A time series is a data vector that is sampled over time and represents the time
evolution of one or more dynamic properties. For more information on the MATLAB time series
support, see the documentation for “Time Series”.
In the case of ROS messages within a rosbag, a time series can help to express the change in
particular message elements through time. You can extract this information through the timeseries
function. This is memory-efficient, since the complete messages do not have to be stored in memory.
Use the same selection, but use the timeseries function to only extract the properties for x-position
and z-axis angular velocity:
ts = timeseries(bagselect3,"Pose.Pose.Position.X","Twist.Twist.Angular.Z")
timeseries
Common Properties:
Name: '/odom Properties'
Time: [101x1 double]
TimeInfo: [1x1 tsdata.timemetadata]
Data: [101x2 double]
DataInfo: [1x1 tsdata.datametadata]
The return of this call is a timeseries object that can be used for further analysis or processing.
Note that this method of extracting data is only supported if the current selection contains a single
topic with a single message type.
To see the data contained within the time series, access the Data property:
ts.Data
ans = 101×2
0.0003 0.0003
0.0003 0.0003
0.0003 -0.0006
0.0003 -0.0006
0.0003 -0.0010
1-84
Work with rosbag Logfiles
0.0003 -0.0010
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0003
0.0003 -0.0003
⋮
There are many other possible ways to work with the time series data. Calculate the mean of the data
columns:
mean(ts)
ans = 1×2
10-3 ×
0.3213 -0.4616
figure
plot(ts,"LineWidth",3)
1-85
1 ROS Featured Examples
The tf system in ROS keeps track of multiple coordinate frames and maintains the relationship
between them in a tree structure. tf is distributed, so that all coordinate frame information is
available to every node in the ROS network. MATLAB® enables you to access this transformation
tree. This example familiarizes you with accessing the available coordinate frames, retrieving
transformations between them, and transform points, vectors, and other entities between any two
coordinate frames.
Prerequisites: “Get Started with ROS” on page 1-40, “Connect to a ROS Network” on page 1-45
Start up
rosinit
There are three coordinate frames that are defined in this transformation tree:
• the transformation from the robot base to the camera's mounting point
• the transformation from the mounting point to the center of the camera
exampleHelperROSStartTfPublisher
1-86
Access the tf Transformation Tree in ROS
Here, the x, y, and z axes of each frame are represented by red, green, and blue lines respectively.
The parent-child relationship between the coordinate frames is shown through a brown arrow
pointing from the child to its parent frame.
Create a new transformation tree object with the rostf function. You can use this object to access all
available transformations and apply them to different entities.
tftree = rostf
tftree =
TransformationTree with properties:
Once the object is created, it starts receiving tf transformations and buffers them internally. Keep the
tftree variable in the workspace so that it continues to receive data.
Pause for a little bit to make sure that all transformations are received.
pause(2);
You can see the names of all the available coordinate frames by accessing the AvailableFrames
property.
tftree.AvailableFrames
1-87
1 ROS Featured Examples
{'mounting_point'}
{'robot_base' }
This should show the three coordinate frames that describe the relationship between the camera, its
mounting point, and the robot.
Receive Transformations
Now that the transformations are available, you can inspect them. Any transformation is described by
a ROS geometry_msgs/TransformStamped message and has a translational and rotational
component.
Retrieve the transformation that describes the relationship between the mounting point and the
camera center. Use the getTransform function to do that.
mountToCamera = getTransform(tftree, 'mounting_point', 'camera_center');
mountToCameraTranslation = mountToCamera.Transform.Translation
mountToCameraTranslation =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 0
Y: 0
Z: 0.5000
quat = mountToCamera.Transform.Rotation
quat =
ROS Quaternion message with properties:
MessageType: 'geometry_msgs/Quaternion'
X: 0
Y: 0.7071
Z: 0
W: 0.7071
mountToCameraRotationAngles = 1×3
0 90 0
Relative to the mounting point, the camera center is located 0.5 meters along the z-axis and is rotated
by 90 degrees around the y-axis.
To inspect the relationship between the robot base and the camera's mounting point, call
getTransform again.
baseToMount = getTransform(tftree, 'robot_base', 'mounting_point');
baseToMountTranslation = baseToMount.Transform.Translation
1-88
Access the tf Transformation Tree in ROS
baseToMountTranslation =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 1
Y: 0
Z: 0
baseToMountRotation = baseToMount.Transform.Rotation
baseToMountRotation =
ROS Quaternion message with properties:
MessageType: 'geometry_msgs/Quaternion'
X: 0
Y: 0
Z: 0
W: 1
The mounting point is located at 1 meter along the robot base's x-axis.
Apply Transformations
Assume now that you have a 3D point that is defined in the camera_center coordinate frame and
you want to calculate what the point coordinates in the robot_base frame are.
Use the waitForTransform function to wait until the transformation between the camera_center
and robot_base coordinate frames becomes available. This call blocks until the transform that takes
data from camera_center to robot_base is valid and available in the transformation tree.
Now define a point at position [3 1.5 0.2] in the camera center's coordinate frame. You will
subsequently transform this point into robot_base coordinates.
pt = rosmessage('geometry_msgs/PointStamped');
pt.Header.FrameId = 'camera_center';
pt.Point.X = 3;
pt.Point.Y = 1.5;
pt.Point.Z = 0.2;
You can transform the point coordinates by calling the transform function on the transformation
tree object. Specify what the target coordinate frame of this transformation is. In this example, use
robot_base.
tfpt =
ROS PointStamped message with properties:
MessageType: 'geometry_msgs/PointStamped'
Header: [1x1 Header]
1-89
1 ROS Featured Examples
tfpt.Point
ans =
ROS Point message with properties:
MessageType: 'geometry_msgs/Point'
X: 1.2000
Y: 1.5000
Z: -2.5000
Besides PointStamped messages, the transform function allows you to transform other entities
like poses (geometry_msgs/PoseStamped), quaternions (geometry_msgs/QuaternionStamped),
and point clouds (sensor_msgs/PointCloud2).
If you want to store a transformation, you can retrieve it with the getTransform function.
robotToCamera =
ROS TransformStamped message with properties:
MessageType: 'geometry_msgs/TransformStamped'
Header: [1x1 Header]
Transform: [1x1 Transform]
ChildFrameId: 'camera_center'
This transformation can be used to transform coordinates in the camera_center frame into
coordinates in the robot_base frame.
robotToCamera.Transform.Translation
ans =
ROS Vector3 message with properties:
MessageType: 'geometry_msgs/Vector3'
X: 1
Y: 0
Z: 0.5000
robotToCamera.Transform.Rotation
ans =
ROS Quaternion message with properties:
1-90
Access the tf Transformation Tree in ROS
MessageType: 'geometry_msgs/Quaternion'
X: 0
Y: 0.7071
Z: 0
W: 0.7071
Send Transformations
Assume that you have a simple transformation that describes the offset of the wheel coordinate
frame relative to the robot_base coordinate frame. The wheel is mounted -0.2 meters along the y-
axis and -0.3 along the z-axis. The wheel has a relative rotation of 30 degrees around the y-axis.
tfStampedMsg = rosmessage('geometry_msgs/TransformStamped');
tfStampedMsg.ChildFrameId = 'wheel';
tfStampedMsg.Header.FrameId = 'robot_base';
The transformation itself is described in the Transform property. It contains a Translation and a
Rotation. Fill in the values that are listed above.
The Rotation is described as a quaternion. To convert the 30 degree rotation around the y-axis to a
quaternion, you can use the axang2quat (Navigation Toolbox) function. The y-axis is described by
the [0 1 0] vector and 30 degrees can be converted to radians with the deg2rad function.
tfStampedMsg.Transform.Translation.X = 0;
tfStampedMsg.Transform.Translation.Y = -0.2;
tfStampedMsg.Transform.Translation.Z = -0.3;
quatrot = 1×4
0.9659 0 0.2588 0
tfStampedMsg.Transform.Rotation.W = quatrot(1);
tfStampedMsg.Transform.Rotation.X = quatrot(2);
tfStampedMsg.Transform.Rotation.Y = quatrot(3);
tfStampedMsg.Transform.Rotation.Z = quatrot(4);
Use rostime to retrieve the current system time and use that to timestamp the transformation. This
lets the recipients know at which point in time this transformation was valid.
tfStampedMsg.Header.Stamp = rostime('now');
sendTransform(tftree, tfStampedMsg)
1-91
1 ROS Featured Examples
The new wheel coordinate frame is now also in the list of available coordinate frames.
tftree.AvailableFrames
The final visual representation of all four coordinate frames looks as follows.
You can see that the wheel coordinate frame has the translation and rotation that you specified in
sending the transformation.
exampleHelperROSStopTfPublisher
Shut down the ROS master and delete the global node.
rosshutdown
1-92
Access the tf Transformation Tree in ROS
See Also
Related Examples
• “Read and Apply Transformation to ROS Message in Simulink” on page 6-87
1-93
1 ROS Featured Examples
This example shows how to handle message types for laser scans, uncompressed and compressed
images, point clouds, camera info, occcupancy grid, and octomap messages.
These are some commonly used ROS messages stored data in a format, that requires some
transformation before it can be used for further processing. MATLAB® can help you by formatting
these specialized ROS messages for easy use.
Load some sample messages. These messages are populated with real and synthetic data from
various robotics sensors.
load("specialROSMessageData.mat")
Image Messages
MATLAB provides support for image messages, which always have the message type sensor_msgs/
Image.
Create an empty image message using rosmessage to see the standard ROS format for an image
message.
emptyimg = rosmessage("sensor_msgs/Image",DataFormat="struct")
For convenience, an image message that is fully populated and is stored in the img variable is loaded
from specialROSMessageData.mat.
Inspect the image message variable img in your workspace. The size of the image is stored in the
Width and Height properties. ROS sends the actual image data using a vector in the Data property.
img
1-94
Work with Specialized ROS Messages
The Data property stores raw image data that cannot be used directly for processing and
visualization in MATLAB. You can use the rosReadImage function to retrieve the image in a format
that is compatible with MATLAB.
imageFormatted = rosReadImage(img);
The original image has a rgb8 encoding. By default, rosReadImage returns the image in a standard
480-by-640-by-3 uint8 format. View this image using the imshow function.
imshow(imageFormatted)
MATLAB® supports all ROS image encoding formats, and rosReadImage handles the complexity of
converting the image data. In addition to color images, MATLAB also supports monochromatic and
depth images.
Additionally, MATLAB provides the rosWriteImage function to convert a MATLAB image to a ROS
message using the function. Apply rudimentary object detection on the sample image with color
thresholding. Visualize the modified image.
1-95
1 ROS Featured Examples
greenPercentage = 100*double(imageFormatted(:,:,2))./sum(imageFormatted,3);
thresholdImg = 255*uint8(greenPercentage > 35);
imshow(thresholdImg)
Write the modified image to a ROS message with the rosWriteImage function. Since the modified
image only has 1 channel and is of type uint8, use the mono8 encoding.
imageMsg = rosWriteImage(emptyimg,thresholdImg,Encoding="mono8");
Many ROS systems send their image data in a compressed format. MATLAB provides support for
these compressed image messages.
Create an empty compressed image message using rosmessage. Compressed images in ROS have
the message type sensor_msgs/CompressedImage and have a standard structure.
emptyimgcomp = rosmessage("sensor_msgs/CompressedImage",DataFormat="struct")
1-96
Work with Specialized ROS Messages
For convenience, a compressed image message that is already populated was loaded from
specialROSMessageData.mat.
Inspect the imgcomp variable that was captured by a camera. The Format property captures all the
information that MATLAB needs to decompress the image data stored in Data.
imgcomp
Similar to the image message, you can use rosReadImage to obtain the image in standard RGB
format. Even though the original encoding for this compressed image is bgr8, rosReadImage does
the conversion.
compressedFormatted = rosReadImage(imgcomp);
imshow(compressedFormatted)
1-97
1 ROS Featured Examples
Most image formats are supported for the compressed image message type. The 16UC1 and 32FC1
encodings are not supported for compressed depth images. Monochromatic and color image
encodings are supported.
Point clouds can be captured by a variety of sensors used in robotics, including LIDARs, Kinect®, and
stereo cameras. The most common message type in ROS for transmitting point clouds is
sensor_msgs/PointCloud2 and MATLAB provides some specialized functions for you to work with
this data.
You can see the standard ROS format for a point cloud message by creating an empty point cloud
message.
emptyptcloud = rosmessage("sensor_msgs/PointCloud2",DataFormat="struct")
1-98
Work with Specialized ROS Messages
PointStep: 0
RowStep: 0
Data: [0x1 uint8]
IsDense: 0
View the populated point cloud message that is stored in the ptcloud variable in your workspace:
ptcloud
The point cloud information is encoded in the Data property of the message. You can extract the
x,y,z coordinates as an N-by-3 matrix by calling the rosReadXYZ function.
xyz = rosReadXYZ(ptcloud)
NaN in the point cloud data indicates that some of the x,y,z values are not valid. This is an artifact of
the Kinect® sensor, and you can safely remove all NaN values.
xyzValid = xyz(~isnan(xyz(:,1)),:)
1-99
1 ROS Featured Examples
Some point cloud sensors also assign RGB color values to each point in a point cloud. If these color
values exist, you can retrieve them with a call to rosReadRGB.
rgb = rosReadRGB(ptcloud)
You can visualize the point cloud with the rosPlot function. rosPlot automatically extracts the
x,y,z coordinates and the RGB color values (if they exist) and show them in a 3-D scatter plot. The
rosPlot function ignores all NaN x,y,z coordinates, even if RGB values exist for that point.
rosPlot(ptcloud)
1-100
Work with Specialized ROS Messages
Examine all the stored fields in the point cloud message using the rosReadAllFieldNames function.
The loaded point cloud message contains four fields x, y, z, and rgb.
fieldNames = rosReadAllFieldNames(ptcloud)
You can access the corresponding data for any field using the rosReadField function. You must
unpack the returned data manually, depending on how it is formatted. For example, the RGB image
can be extracted by type casting the data to uint8 and reshaping the result. Use the result from the
rosReadAllFieldNames function for input validation.
if any(contains(fieldNames,"rgb"))
rawData = typecast(rosReadField(ptcloud,"rgb"),"uint8");
tmp = reshape(permute(reshape(rawData,4,[]),[3,2,1]),ptcloud.Width,ptcloud.Height,4);
pcImg = permute(tmp(:,:,[3,2,1]),[2 1 3]);
imshow(pcImg)
end
1-101
1 ROS Featured Examples
Calculate the intensity value of each point in the point cloud as 1/3(r+g+b), where r, g, and b are
the RGB color values of that point, respectively.
intensity = sum(rgb,2)/3;
Write the x, y, z, RGB, and intensity values to the empty point cloud message using rosWriteXYZ,
rosWriteRGB, and rosWriteIntensity functions respectively. Specify a point step size of 32.
ptcloudWithIntensity = rosWriteXYZ(emptyptcloud,xyz,PointStep=uint32(32));
ptcloudWithIntensity = rosWriteRGB(ptcloudWithIntensity,rgb);
ptcloudWithIntensity = rosWriteIntensity(ptcloudWithIntensity,intensity)
1-102
Work with Specialized ROS Messages
Octomap Messages
ROS uses Octomap messages to implement 3D occupancy grids. Octomap messages are commonly
used in robotics applications, such as 3D navigation. You can see the standard ROS format for an
octomap message by creating an empty message of the appropriate type.
emptyoctomap = rosmessage("octomap_msgs/Octomap",DataFormat="struct")
For convenience, an octomap message that is fully populated and is stored in the octomap variable
loaded from specialROSMessageData.mat.
Inspect the variable octomap in your workspace. The Data field contains the octomap structure in a
serialized format.
octomap
Create an occupancyMap3D (Navigation Toolbox) object from the ROS message using the
rosReadOccupancyMap3D function. Display the 3D occupancy map using the show function.
occupancyMap3DObj = rosReadOccupancyMap3D(octomap);
show(occupancyMap3DObj)
1-103
1 ROS Featured Examples
Quaternion Messages
Quaternions are commonly used in robotics to express orientation. Use rosmessage to create a
quaternion message and observe the fields.
emptyquatmsg = rosmessage("geometry_msgs/Quaternion",DataFormat="struct")
For convenience, a quaternion message that represents a 90 degree rotation about the z-axis was
loaded from specialROSMessageData.mat. Inspect the variable quatMsg in your workspace.
quatmsg
1-104
Work with Specialized ROS Messages
Z: 0.7071
W: 0.7071
Create a quaternion object from a ROS message using the rosReadQuaternion function. The
quaternion object contains the x, y, z, and w components and provides additional functionalities,
such as rotating a point.
quat = rosReadQuaternion(quatmsg);
Define a point in three-dimensional space and rotate it using rotatepoint function. Visualize the
two points
cartesianPoint = [1,0,1];
plot3(cartesianPoint(1),cartesianPoint(2),cartesianPoint(3),"bo")
hold on
plot3([0;cartesianPoint(1)],[0;cartesianPoint(2)],[0;cartesianPoint(3)],"k")
rotationResult = rotatepoint(quat,cartesianPoint);
plot3(rotationResult(1),rotationResult(2),rotationResult(3),"ro")
plot3([0;rotationResult(1)],[0;rotationResult(2)],[0;rotationResult(3)],"k")
xlabel("x")
ylabel("y")
zlabel("z")
grid on
1-105
1 ROS Featured Examples
Camera calibration is a commonly used procedure in robotics vision applications. ROS provides
sensor_msgs/CameraInfo message type to publish calibration information. Use rosmessage to
create a camera info message and observe the fields.
emptycamerainfomsg = rosmessage("sensor_msgs/CameraInfo",DataFormat="struct")
Notably, the message stores the matrices K and P as vectors. ROS requires these matrices to be
stored in row-major format. MATLAB stores matrices in column-major, hence extracting the K and P
matrices requires reshaping and transposing.
For convenience, the variable params loaded from calibrationStructs.mat is a fully populated
cameraParameters struct. Write the cameraParameters struct to a new ROS message using the
rosWriteCameraInfo function.
msg = rosWriteCameraInfo(emptycamerainfomsg,params);
The following table shows the correspondence between the cameraParameters object and the ROS
message.
exampleHelperShowCameraParametersTable
ans=5×2 table
ROS message camera parameters
___________ ______________________
Verify that the intrinsic matrix of the ROS message matches the intrinsic matrix of params.
1-106
Work with Specialized ROS Messages
K = reshape(msg.K,3,3)'
K = 3×3
714.1885 0 563.6481
0 710.3785 355.7254
0 0 1.0000
intrinsicMatrix = params.IntrinsicMatrix'
intrinsicMatrix = 3×3
714.1885 0 563.6481
0 710.3785 355.7254
0 0 1.0000
The following table shows the correspondence between the stereoParameters object and the ROS
message.
exampleHelperShowStereoParametersTable
ans=2×2 table
ROS message stereoParameters
____________ ___________________________
Verify that the camera 2 rotation matrices of the ROS message and stereoParams match.
R1 = reshape(msg1.R,3,3)';
R2 = reshape(msg2.R,3,3)';
R = R1\R2
R = 3×3
rotationOfCamera2 = stereoParams.RotationOfCamera2
rotationOfCamera2 = 3×3
Verify that the camera 2 translation vectors of the ROS message and stereoParams match.
1-107
1 ROS Featured Examples
P = reshape(msg2.P,4,3)';
P(1:2,end)'
ans = 1×2
-119.8720 -0.4005
translationOfCamera2 = stereoParams.TranslationOfCamera2(1:2)
translationOfCamera2 = 1×2
-119.8720 -0.4005
Laser scanners are commonly used sensors in robotics. ROS provides sensor_msgs/LaserScan
message type to publish laser scan messages. Use rosmessage to create a laser scan message and
observe the fields.
emptyscan = rosmessage("sensor_msgs/LaserScan","DataFormat","struct")
Since you created an empty message, emptyscan does not contain any meaningful data. For
convenience, a laser scan message that is fully populated and is stored in the scan variable was
loaded from specialROSMessageData.mat.
Inspect the scan variable. The primary data in the message is in the Ranges property. The data in
Ranges is a vector of obstacle distances recorded at small angle increments.
scan
1-108
Work with Specialized ROS Messages
You can get the scan angles from the ROS message using the rosReadScanAngles function.
Visualize the scan data in polar coordinates using the polarPlot function.
angles = rosReadScanAngles(scan);
figure
polarplot(angles,scan.Ranges,LineWidth=2)
title("Laser Scan")
You can get the measured points in Cartesian coordinates using the rosReadCartesian function.
xy = rosReadCartesian(scan);
This populates xy with a list of [x,y] coordinates that were calculated based on all valid range
readings. Visualize the scan message using the rosPlot function:
rosPlot(scan,"MaximumRange",5)
1-109
1 ROS Featured Examples
Create a lidarScan object from a ROS message using the rosReadLidarScan function. The
lidarScan object contains ranges, angles, and Cartesian points and provides additional
functionalities, such as transforming the scanned points. Use the transformScan function to rotate
the scan point and visualize it using plot.
lidarScanObj = rosReadLidarScan(scan)
lidarScanObj =
lidarScan with properties:
rotateScan = transformScan(lidarScanObj,[0,0,pi/2]);
plot(rotateScan)
1-110
Work with Specialized ROS Messages
Occupancy grid messages are commonly used in robotics for 2D navigation applications. ROS
provides nav_msgs/OccupancyGrid message type to publish occupancy grid messages. Use
rosmessage to create an occupancy grid message and observe the fields.
emptyMap = rosmessage("nav_msgs/OccupancyGrid",DataFormat="struct")
Notice that emptyMap does not contain any meaningful data. For convenience, an occupancy grid
message that is fully populated and is stored in the mapMsg variable loaded from
specialROSMessageData.mat.
Inspect the mapMsg variables. The occupancy grid values are encoded in the Data field.
mapMsg
1-111
1 ROS Featured Examples
occupancyMapObj = rosReadOccupancyGrid(mapMsg);
show(occupancyMapObj);
You can use the occupancyMap (Navigation Toolbox) object functions to manipulate the occupancy
grid. Use the inflate function to expand the occupied regions. Write the occupancyMap object to a
new ROS message using the rosWriteOccupancyGrid function. Use the show function to display
the new occupancy grid.
inflate(occupancyMapObj,5)
occupancyMapInflatedMsg = rosWriteOccupancyGrid(mapMsg,occupancyMapObj);
show(occupancyMapObj);
1-112
Work with Specialized ROS Messages
Alternatively, you can create a binaryOccupancyMap (Navigation Toolbox) object from a ROS
occupancy grid message using the rosReadBinaryOccupancyGrid function. A binary occupancy
map holds discrete occupancy values of 0 or 1 at each cell whereas an occupancy map holds
probability occupancy values that range between 0 and 1 at each cell. Use the show function to
display the binary occupancy grid.
binaryMapObj = rosReadBinaryOccupancyGrid(mapMsg);
show(binaryMapObj);
1-113
1 ROS Featured Examples
Similarly, you can use the binaryOccupancyMap (Navigation Toolbox) object functions to manipulate
the binary occupancy grid. Use the inflate function to alter the binary occupancy grid and create a
new ROS message using the rosWriteBinaryOccupancyGrid function. Use the show function to
display the new binary occupancy grid.
inflate(binaryMapObj,5)
binaryMapInflatedMsg = rosWriteBinaryOccupancyGrid(mapMsg,binaryMapObj);
show(binaryMapObj);
1-114
Work with Specialized ROS Messages
1-115
1 ROS Featured Examples
This example shows how to handle VelodyneScan messages from a Velodyne LiDAR.
Velodyne ROS messages store data in a format that requires some interpretation before it can be
used for further processing. MATLAB® can help you by formatting Velodyne ROS messages for easy
use.
Load sample Velodyne messages. These messages are populated with data gathered from Velodyne
LiDAR sensor.
load("lidarData_ConstructionRoad.mat")
VelodyneScan Messages
VelodyneScan messages are ROS messages that contain Velodyne LIDAR scan packets. You can see
the standard ROS format for a VelodyneScan message by creating an empty message of the
appropriate type. Use messages in structure format for better performance.
emptyveloScan = rosmessage("velodyne_msgs/VelodyneScan","DataFormat","struct")
Since you created an empty message, emptyveloScan does not contain any meaningful data. For
convenience, the loaded lidarData_ConstructionRoad.mat file contains a set of VelodyneScan
messages that are fully populated and stored in the msgs variable. Each element in the msgs cell
array is a VelodyneScan ROS message struct. The primary data in each VelodyneScan message is
in the Packets property, it contains multiple VelodynePacket messages. You can see the standard
ROS format for a VelodynePacket message by creating an empty message of the appropriate type.
emptyveloPkt = rosmessage("velodyne_msgs/VelodynePacket","DataFormat","struct")
The velodyneROSMessageReader object reads point cloud data from VelodyneScan ROS
messages based on their specified model type. Note that providing an incorrect device model may
result in improperly calibrated point clouds. This example uses messages from the "HDL32E" model.
veloReader = velodyneROSMessageReader(msgs,"HDL32E")
veloReader =
velodyneROSMessageReader with properties:
1-116
Work with Velodyne ROS Messages
You can extract point clouds from the raw packets message with the help of this
velodyneROSMessageReader object. By providing a specific frame number or timestamp, one point
cloud can be extracted from velodyneROSMessageReader object using the readFrame object
function. If you call readFrame without a frame number or timestamp, it extracts the next point
cloud in the sequence based on the CurrentTime property.
Create a duration scalar that represents one second after the first point cloud reading.
Read the first point cloud recorded at or after the given time duration.
ptCloudObj = readFrame(veloReader,timeDuration);
ptCloudLoc = ptCloudObj.Location;
reset(veloReader)
You can also loop through all point clouds in the input Velodyne ROS messages.
Define x-, y-, and z-axes limits for pcplayer in meters. Label the axes.
player = pcplayer(xlimits,ylimits,zlimits);
xlabel(player.Axes,"X (m)");
ylabel(player.Axes,"Y (m)");
zlabel(player.Axes,"Z (m)");
The first point cloud of interest is captured at 0.3 second into the input messages. Set the
CurrentTime property to that time to begin reading point clouds from there.
1-117
1 ROS Featured Examples
Display the point cloud stream for 2 seconds. To check if a new frame is available and continue past 2
seconds, remove the last while condition. Iterate through the file by calling readFrame to read in
point clouds. Display them using the point cloud player.
1-118
Get Started with a Real TurtleBot
This example shows how to connect to a TurtleBot® using the MATLAB® ROS interface. You can use
this interface to connect to a wide range of ROS-supported hardware from MATLAB. If you are using
a TurtleBot in Gazebo® refer to the “Get Started with Gazebo and Simulated TurtleBot” on page 1-
205 example.
The following steps use the TurtleBot 3 Waffle Pi platform (https://www.turtlebot.com/). The kit comes
with a Raspberry Pi that has a pre-installed copy of ROS with the appropriate TurtleBot software.
This procedure assumes that you are using a new TurtleBot of similar configuration. If you are
already using a TurtleBot and communicating with it through an external computer, do not perform
this procedure.
1-119
1 ROS Featured Examples
• Unpack the TurtleBot and make sure the power source is connected.
• Turn on the Raspberry Pi.
1-120
Get Started with a Real TurtleBot
• Make sure that you have a network set up to connect the host computer (the one with MATLAB) to
the Raspberry Pi on this TurtleBot. Use a wireless router or an Ethernet cable.
• Open a terminal on the Raspberry Pi and run ifconfig. The IP address associated with the
network that you connected to is displayed.
• Set the appropriate environment variables on the TurtleBot by executing the following commands.
Execute these command only once.
Make sure that you can ping the host machine from the Raspberry Pi:
ping IP_OF_HOST_COMPUTER
A successful ping is shown on the left. An unsuccessful ping is shown on the right.
1-121
1 ROS Featured Examples
Note: These environment variables must always have the correct IP address assigned to the
TurtleBot. If the IP address of the TurtleBot Raspberry Pi changes, you must also change the
environment variables using the preceding commands.
1-122
Get Started with a Real TurtleBot
Type the following commands in separate terminals on the TurtleBot Raspberry Pi to launch LiDAR
and camera sensors in TurtleBot 3:
1-123
1 ROS Featured Examples
If you have a TurtleBot with a different setup from the setup previously described, before trying to
communicate through MATLAB make sure that the following information is true:
• You have set up your network so that you can ping the host machine.
• You have access to the following topics. On the TurtleBot Raspberry Pi, type rostopic list to
see the topics.
/odom
/cmd_vel
/reset
/scan
• On the network, find the IP address of your host computer. On a Windows® machine, at the
command prompt, type ipconfig. On a Mac or Linux® machine, open a terminal and type
ifconfig. Here is an example of ipconfig:
1-124
Get Started with a Real TurtleBot
ping IP_OF_TURTLEBOT
1-125
1 ROS Featured Examples
Next Steps
• Refer to the next example: “Communicate with the TurtleBot” on page 1-243
1-126
Get Started with ROS in Simulink
This example shows how to use Simulink® blocks for ROS to send and receive messages from a local
ROS network.
Introduction
Simulink support for Robot Operating System (ROS) enables you to create Simulink models that work
with a ROS network. ROS is a communication layer that allows different components of a robot
system to exchange information in the form of messages. A component sends a message by
publishing it to a particular topic, such as /odometry. Other components receive the message by
subscribing to that topic.
Simulink support for ROS includes a library of Simulink blocks for sending and receiving messages
for a designated topic. When you simulate the model, Simulink connects to a ROS network, which can
be running on the same machine as Simulink or on a remote system. Once this connection is
established, Simulink exchanges messages with the ROS network until the simulation is terminated.
If Simulink Coder™ is installed, you can also generate C++ code for a standalone ROS component, or
node, from the Simulink model.
Prerequisites: “Create a Simple Model” (Simulink), “Get Started with ROS” on page 1-40
Model
You will use Simulink to publish the X and Y location of a robot. You will also subscribe to the same
location topic and display the received X,Y location.
Enter the following command to open the completed model created in example.
open_system('robotROSGetStartedExample');
Initialize ROS
Every ROS network has a ROS master that coordinates all the parts of the ROS network. For this
example, use MATLAB® to create a ROS master on your local system. Simulink automatically detects
and uses the local ROS master.
rosinit
Create a Publisher
Configure a block to send a geometry_msgs/Point message to a topic named /location (the "/"
is standard ROS syntax).
• From the MATLAB Toolstrip, select Home > Simulink to open Simulink Start Page.
1-127
1 ROS Featured Examples
• On Simulink Start Page, under Simulink, click Blank Model to create and open a new Simulink
Model.
• From the Simulink Toolstrip, select Simulation > Library Browser to open the Simulink Library
Browser. Click on the ROS Toolbox tab (you can also type roslib in MATLAB command window).
Select the ROS Library.
• Drag a Publish block to the model. Double-click on the block to configure the topic and message
type.
• Select Specify your own for the Topic source, and enter /location in Topic.
• Click Select next to Message type. A pop-up window will appear. Select geometry_msgs/Point
and click OK to close the pop-up window.
1-128
Get Started with ROS in Simulink
1-129
1 ROS Featured Examples
Create a blank ROS message and populate it with the X and Y location for the robot path. Then
publish the updated ROS message to the ROS network.
A ROS message is represented as a bus signal in Simulink. A bus signal is a bundle of Simulink
signals, and can also include other bus signals (see the “Explore Simulink Bus Capabilities”
(Simulink) example for an overview). The ROS Blank Message block outputs a Simulink bus signal
corresponding to a ROS message.
• Click ROS Toolbox tab in the Library Browser, or type roslib at the MATLAB command line.
Select the ROS Library.
• Drag a Blank Message block to the model. Double-click on the block to open the block mask.
• Click on Select next to the Message type box, and select geometry_msgs/Point from the
resulting pop-up window. Click OK to close the block mask.
• From the Simulink > Signal Routing tab in the Library Browser, drag a Bus Assignment block.
• Connect the output port of the Blank Message block to the Bus input port of the Bus
Assignment block. Connect the output port of the Bus Assignment block to the input port of
ROS Publish block.
• Double-click on the Bus Assignment block. You should see X, Y and Z (the signals comprising a
geometry_msgs/Point message) listed on the left. Select ??? signal1 in the right listbox and
click Remove. Select both X and Y signals in the left listbox and click Select. Click OK to apply
changes.
NOTE: If you do not see X, Y and Z listed, close the block mask for the Bus Assignment block, and
under the Modeling tab, click Update Model to ensure that the bus information is correctly
propagated. If you see the error, "Selected signal 'signal1' in the Bus Assignment block cannot be
found", it indicates that the bus information has not been propagated. Close the Diagnostic Viewer,
and repeat the above step.
You can now populate the bus signal with the robot location.
• From the Simulink > Sources tab in the Library Browser, drag two Sine Wave blocks into the
model.
• Connect the output ports of each Sine Wave block to the assignment input ports X and Y of the
Bus Assignment block.
• Double-click on the Sine Wave block that is connected to input port X. Set the Phase parameter
to -pi/2 and click OK. Leave the Sine Wave block connected to input port Y as default.
1-130
Get Started with ROS in Simulink
At this point, the model is set up to publish messages to the ROS network. You can verify this as
follows:
• Under the Simulation tab, set the simulation stop time to inf.
• Click Run to start simulation. Simulink creates a dedicated ROS node for the model and a ROS
publisher corresponding to the Publish block.
• While the simulation is running, type rosnode list in the MATLAB command window. This lists
all the nodes available in the ROS network, and includes a node with a name like /
untitled_81473 (the name of the model along with a random number to make it unique).
• While the simulation is running, type rostopic list in the MATLAB command window. This lists
all the topics available in the ROS network, and it includes /location.
• Click Stop to stop the simulation. Simulink deletes the ROS node and ROS publisher. In general,
the ROS node for a model and any associated publishers and subscribers are automatically
deleted at the end of a simulation; no additional clean-up steps are required.
Create a Subscriber
Use Simulink to receive messages sent to the /location topic. You will extract the X and Y location
from the message and plot it in the XY-plane.
• From the ROS Toolbox tab in the Library Browser, drag a Subscribe block to the model. Double-
click on the block.
1-131
1 ROS Featured Examples
• Select Specify your own in the Topic source box, and enter /location in the Topic box.
• Click Select next to the Message type box, and select geometry_msgs/Point from the pop-up
window. Click OK to close the block mask.
The Subscribe block outputs a Simulink bus signal, so you need to extract the X and Y signals from
it.
• From the Simulink > Signal Routing tab in the Library Browser, drag a Bus Selector block to
the model.
• Connect the Msg output of the Subscribe block to the input port of the Bus Selector block.
• From the Modeling tab, select Update Model to ensure that the bus information is propagated.
You may get errors and they will be resolved by the next step.
• Double-click on the Bus Selector block. Select signal1 and signal2 in the right listbox and
click to remove them. Select both X and Y signals in the left listbox and click to select
the signals. Click OK.
The Subscribe block will output the most-recently received message for the topic on every time step.
The IsNew output indicates whether the message has been received during the prior time step. For
the current task, the IsNew output is not needed, so do the following:
• From the Simulink > Sinks tab in the Library Browser, drag a Terminator block to the model.
• Connect the IsNew output of the Subscribe block to the input of the Terminator block.
The remaining steps configure the display of the extracted X and Y signals.
• From the Simulink > Sinks tab in the Library Browser, drag an XY Graph block to the model.
Connect the output ports of the Bus Selector block to the input ports of the XY Graph block.
• From the Simulink > Sinks tab in the Library Browser, drag two Display blocks to the model.
Connect each output of the Bus Selector block to each Display block.
• Save your model.
1-132
Get Started with ROS in Simulink
• From the Modeling tab, select Model Settings. In the Solver pane, set Type to Fixed-step and
Fixed-step size to 0.01.
• Set simulation stop time to 10.0.
• Click Run to start simulation. An XY plot will appear.
1-133
1 ROS Featured Examples
The first time you run the model in Simulink, the XY plot may look more jittery than the one above
due to delays caused by loading ROS libraries. Once you rerun the simulation a few times, the plot
should look smoother.
Note that the simulation does not work in actual or "real" time. The blocks in the model are
evaluated in a loop that only simulates the progression of time, and is not intended to track actual
clock time (for details, see “Simulation Loop Phase” (Simulink)).
In the above model, the Subscribe block outputs a message (bus signal) on every time step; if no
messages have been received at all, it outputs a blank message (i.e., a message with zero values).
Consequently, the XY coordinates are initially plotted at (0,0).
In this task, you will modify the model to use an Enabled Subsystem, so that it plots the location
only when a new message is received (for more information, see “Using Enabled Subsystems”
(Simulink)). A pre-configured model is included for your convenience.
• In the model, click and drag to select the Bus Selector block and XY Graph blocks. Right-click
on the selection and select Create Subsystem from Selection.
• From the Simulink > Ports & Subsystems tab in the Library Browser, drag an Enable block
into the newly-created subsystem.
• Connect the IsNew output of the Subscribe block to the enabled input of the subsystem as shown
in the picture below. Delete the Terminator block. Note that the IsNew output is true only if a
new message was received during the previous time step.
1-134
Get Started with ROS in Simulink
The blocks in the enabled subsystem are only executed when a new ROS message is received by the
Subscribe block. Hence, the initial (0,0) value will not be displayed in the XY plot.
1-135
1 ROS Featured Examples
This example illustrates how to work with complex ROS messages in Simulink, such as messages with
nested sub-messages and variable-length arrays.
Introduction
In ROS Simulink Models, bus signals represent ROS Messages. Each field of a ROS message is
corresponds to a field in a Simulink bus, with the following limitations:
• Constants are not supported, and are excluded from the Simulink bus.
• Variable-length arrays (ROS type ...[]) convert to fixed-length array with customizable
maximum lengths. By default, the fixed length is 128 for primitive types (e.g., uint8[],
float32[]), and 16 for nested arrays of messages (e.g., geometry_msgs/Point[]).
• Strings (ROS type string) convert to fixed-length uint8 arrays with customizable maximum
lengths, with a default maximum length of 128 characters.
• String arrays (ROS type string[]) convert to a fixed-length array of std_msgs/String with a
customizable maximum length. The default maximum length is 16 strings.
When a Simulink bus converts to a ROS message, the message fields restore to their native ROS
types. For example, the ROS message type std_msgs/Header has a field, FrameId, which is a
string. In the corresponding Simulink bus, the FrameId field is a uint8 array. When the bus converts
to a ROS message, FrameId converts back to a string.
Model
The following model has several examples of working with complex ROS messages in Simulink. The
rest of the tasks in this example focus on specific scenarios.
open_system('robotROSMessageUsageExample');
A ROS message can have arrays whose length (number of elements) cannot be pre-determined. For
example, the Position field in a sensor_msgs/JointState message is a variable-length array of
64-bit floats. In any given sensor_msgs/JointState message, the Position array can have no
elements or it can have an arbitrarily large number of elements. In Simulink, such arrays are
required to have a maximum length.
Open the example model and explore how variable-length arrays in ROS messages are handled in
Simulink in the following steps.
open_system('robotROSMessageUsageExample/Work with Variable-length Arrays');
• Double-click the Work with Variable-length Arrays subsystem. Note that the Subscribe block
is configured to receive messages sent to topic /my_joint_topic as message type,
sensor_msgs/JointState.
• Under the Modeling tab, click Update Model.
• Double-click on the Bus Selector block. There are three variable-length arrays in the message
(Position, Velocity, and Effort).
• Observe that there is a Position_SL_Info field in the bus.
Position_SL_Info.ReceivedLength holds the length of the Position array in the original
1-136
Work with ROS Messages in Simulink
• Under the Simulation tab, select ROS Network from the Prepare section. If you do not see ROS
Toolbox, select Robot Operating System (ROS) on the Apps tab, under Control Systems. In the
dialog box that opens up, select Robot Operating System (ROS) from the ROS Network drop-
down.
• Set the Network Address for both ROS Master (ROS 1) and Node Host (ROS 1) to Default.
Run Simulation
• Under the Simulation tab, set Stop Time to Inf, and click Play to start simulation.
• Execute the following at the MATLAB command line.
• Observe the Display outputs in the Work with Variable-length Arrays subsystem. Note that
Current Length and Received Length are equal.
• Execute the following at the MATLAB command line.
1-137
1 ROS Featured Examples
• Observe that a warning is emitted, indicating that a truncation has happened. The Received
Length is now 130 and Current Length is 128.
• Under the Debug tab, select Diagnostics > Diagnostic Viewer. Warnings are typically routed
here to the Simulink Diagnostic Viewer (see “View Diagnostics” (Simulink)).
Change the maximum size of a variable-length array in Simulink. The default maximum of the
Position array in the sensor_msgs/JointState message type is 128. You will change this limit
to 256.
• Open the example model, and double-click on the Work with Variable-length Arrays subsystem.
• From the Simulation tab, select ROS Toolbox > Variable Size Messages.
• From the list box on the left, click on sensor_msgs/JointState. Then, unselect the Use
default limits for this message type checkbox. Finally, enter the new value (256) in the row for
the Position array property, and click OK to close the dialog.
• Run the following at the MATLAB command line. Observe that a warning is emitted in the
Diagnostic Viewer.
1-138
Work with ROS Messages in Simulink
Note:
The Bus Assignment block in Simulink does not support assigning to an element inside an array of
buses.
Explore how to use the MATLAB Function block for advanced message manipulation such as
assignment of nested messages.
• Open the example model. Select the Work with Nested Arrays of Messages subsystem and
copy.
• Open a new Simulink model. Paste and save the new model to a temporary location, with the name
FunctionTest.slx.
• Close all models, and clear the base workspace by typing clear in the MATLAB command line.
• Open the FunctionTest.slx model, double-click on the Work with Nested Arrays of Messages
subsystem, and open the MATLAB Function - Assign block. Observe that it uses MATLAB
notation to assign values inside a nested array.
• The Function Block requires the datatype of bus outputs (in this case, msg) to be explicitly
specified. Create all buses required for this model by typing the following at the MATLAB
command line. Note that the bus objects are created using the name
SL_Bus_<modelname>_<messageType> and stored in the Simulink data dictionary robotlib.
You can find this data dictionary under External Data > From Libraries in Model Explorer.
(The bus names may be abbreviated if the model name is too long.)
ros.createSimulinkBus(gcs)
• Double-click the MATLAB Function - Assign block. In the MATLAB Editor toolstrip, under
Modeling tab, click Symbols Pane. Then right click on msg, select Inspect and set its type to
SL_Bus_FunctionTest_geometry_msgs_PoseArray. Click Apply and close Ports and Data
Manager.
• If you do not see SL_Bus_FunctionTest_geometry_msgs_PoseArray listed as an option in
the Type dropdown, select Refresh data types.
1-139
1 ROS Featured Examples
• If you are using variable-size messages within MATLAB Function block, you must enable Dynamic
memory allocation in MATLAB functions setting under Model Settings > Simulation
Target > Advanced parameters.
• Under the Simulation tab, select ROS Toolbox > ROS Network.
• Set the Network Address for both ROS Master (ROS 1) and Node Host (ROS 1) to Default.
• Enter rosinit at the MATLAB command line.
Run Simulation
• Under the Simulation tab, set Stop Time to 1.0, and click Play to run the simulation. Verify that
the values in the Display blocks are equal to pi/2 and pi/2 + 1.
• The ros.createSimulinkBus(gcs) statement has to be re-run each time the model is loaded.
To avoid these issues, include this statement in the InitFcn callback for the model (see “Model
Callback Parameters” (Simulink)).
1-140
Work with ROS Messages in Simulink
By default, the maximum number of std_msgs/String messages in a string array is 16, and the
maximum length of an individual string is 128 characters. The following steps show how to change
these defaults:
Open the example model, and double-click the Work with Strings and String Arrays subsystem.
• From the Simulation tab, select ROS Toolbox > Variable Size Messages.
• In the Message types in model column, click on the sensor_msgs/JointState entry. Observe
that the right-hand pane shows a Name property that is an array of std_msgs/String, with a
maximum length of 16. To change the maximum number of strings in Name, deselect the Use
default limits for this message type checkbox and enter the desired value.
• In the Message types in model column, click on the std_msgs/String entry. Observe that the
right-hand pane shows a Data property that is an array of uint8, with a maximum length of 128.
To change the maximum length of the string, deselect the Use default limits for this message
type checkbox and enter the desired value.
• Once you change the default values, open the Work with Strings and String Arrays subsystem
and simulate the model. The Display blocks should now reflect the updated maximum values.
Note: The maximum length of Data applies to all instances of std_msgs/String in the model. For
example, the Blank String block in Work with Strings and String Arrays subsystem uses a
std_msgs/String message, so these messages would inherit the updated maximum length.
Likewise, if the model has another ROS message type with a string array property, the individual
strings in that array will also inherit the updated maximum length.
1-141
1 ROS Featured Examples
You can use Simulink® to connect to a ROS-enabled physical robot or to a ROS-enabled robot
simulator such as Gazebo. This example shows how to configure Simulink to connect to a separate
robot simulator using ROS. It then shows how to send velocity commands and receive position
information from a simulated robot.
You can follow the steps in the example to create your own model, or you can use this completed
version instead.
open_system('robotROSConnectToRobotExample');
Prerequisites: “Get Started with ROS” on page 1-40, “Exchange Data with ROS Publishers and
Subscribers” on page 1-60, “Get Started with ROS in Simulink” on page 1-127.
Robot Simulator
Start a ROS-based simulator for a differential-drive robot. The simulator receives and sends messages
on the following topics:
You can choose one of two options for setting up the ROS-based simulator.
Use a simple MATLAB-based simulator to plot the current location of the robot in a separate figure
window.
• Enter rosinit at the MATLAB command line. This creates a local ROS master with network
address (URI) of http://localhost:11311.
• Enter ExampleHelperSimulinkRobotROS to start the Robot Simulator:
1-142
Connect to a ROS-enabled Robot from Simulink
• See “Add, Build, and Remove Objects in Gazebo” on page 1-213 for instructions on setting up the
Gazebo environment. In the Ubuntu® desktop in the virtual machine, click the "Gazebo Empty"
icon.
• Note the network address (URI) of the ROS master. It will look like http://
192.168.84.128:11311, but with your specific IP address.
• Verify that the Gazebo environment is properly set up by typing the rostopic list in the Ubuntu
terminal window. You should see a list of topics, including /cmd_vel and /odom.
• Note: The geometry_msgs/Twist velocity command messages are received on the /cmd_vel
topic.
1. From the Simulation tab, select ROS Toolbox > ROS Network.
1-143
1 ROS Featured Examples
2. In the ROS Master (ROS 1) section, select Custom from the Network Address dropdown.
• Option A (MATLAB Simulator): Ensure that the Hostname/IP Address is set to localhost, and
Port is set to 11311.
• Option B (Gazebo Simulator): Specify the IP address and port number of the ROS master in
Gazebo. For example, if it is http://192.168.60.165:11311, then enter 192.168.60.165 in
the Hostname/IP address box and 11311 in the Port box.
Create a publisher that sends control commands (linear and angular velocities) to the simulator.
Make these velocities adjustable by using Slider Gain blocks.
ROS uses a right-handed coordinate system, so X-axis is forward, Y-axis is left, and Z-axis is up.
Control commands are sent using a geometry_msgs/Twist message, where Linear.X indicates
linear forward velocity (in m/s), and Angular.Z indicates angular velocity around the Z-axis (in
rad/s).
1 From the ROS Toolbox > ROS tab in the Library Browser, drop a Blank Message block to the
model. Double-click the block.
2 Click Select next to Message type and select geometry_msgs/Twist.
1-144
Connect to a ROS-enabled Robot from Simulink
• Add a Constant block, a Gain block, and two Slider Gain blocks. Connect them together as
shown in the figure, and set the Gain value to -1.
• Set the limits and current parameters of the linear velocity slider to 0.0 to 2.0, and 1.0
respectively. Set the corresponding parameters of the steering gain slider to -1.0 to 1.0, and
0.1.
Create a subscriber to receive messages sent to the /odom topic. Extract the location of the robot and
plot it's path in the XY-plane.
1-145
1 ROS Featured Examples
2 Connect the output port of the Subscribe block to the input port of the Bus Selector block. In
the Modeling tab, click Update Model to ensure that the bus information is correctly
propagated.
3 Double-click the Bus Selector block. Select signal1 and signal2 in the right listbox and click
to remove them. In the left listbox, expand Pose > Pose > Position and select X and Y.
This figure shows the completed model. A pre-configured model is included for your convenience.
• Note: The Publisher block in this model uses the /mobile_base/commands/velocity topic for
use with MATLAB simulator option. For Gazebo simulator option, select the /cmd_vel topic as
shown above on page 1-144.
1 From the Modeling tab, click Model Settings. In the Solver pane, set Type to Fixed-step and
Fixed-step size to 0.01.
2 Set simulation Stop time to Inf.
3 Click Run to start the simulation.
4 In both the simulator and XY plot, you should see the robot moving in a circle.
1-146
Connect to a ROS-enabled Robot from Simulink
5 While the simulation is running, change the values of Slider Gain blocks to control the robot.
Double-click the XY Graph block and change the X and Y axis limits if needed. (You can do this
while the simulation is running.)
6 To stop the simulation, click Stop.
1-147
1 ROS Featured Examples
This example involves a model that implements a simple closed-loop proportional controller. The
controller receives location information from a simulated robot (running in a separate ROS-based
simulator) and sends velocity commands to drive the robot to a specified location. Adjust parameters
while the model is running and observe the effect on the simulated robot.
The following figure summarizes the interaction between Simulink and the robot simulator (the
arrows in the figure indicate ROS message transmission). The /odom topic conveys location
information, and the /mobile_base/commands/velocity topic conveys velocity commands.
Follow the steps in the “Connect to a ROS-enabled Robot from Simulink” on page 1-142 example to
do the following:
open_system('robotROSFeedbackControlExample.slx');
1-148
Feedback Control of a ROS-Enabled Robot
The model implements a proportional controller for a differential-drive mobile robot. At each time
step, the algorithm orients the robot toward the desired location and drives it forward. Once the
desired location is reached, the algorithm stops the robot.
open_system('robotROSFeedbackControlExample/Proportional Controller');
Note that there are four tunable parameters in the model (indicated by colored blocks).
• Desired Position (at top level of model): The desired location in (X,Y) coordinates
• Distance Threshold: The robot stops if it is closer than this distance from the desired location
• Linear Velocity: The forward linear velocity of the robot
• Gain: The proportional gain when correcting the robot orientation
The model also has a Simulation Rate Control block (at top level of model). This block ensures that
the simulation update intervals follow wall-clock elapsed time.
Run the model and observe the behavior of the robot in the robot simulator.
• Position windows on your screen so that you can observe both the Simulink model and the robot
simulator.
• Click Play to start simulation.
• While the simulation is running, double-click the Desired Position block and change the
Constant value to [2 3]. Observe that the robot changes its heading.
• While the simulation is running, open the Proportional Controller subsystem and double-click
the Linear Velocity (slider) block. Move the slider to 2. Observe the increase in robot velocity.
• Click Stop to end the simulation.
Use the MATLAB-based simulator to observe the timing and rate of incoming messages.
1-149
1 ROS Featured Examples
The synchronization with wall-clock time is due to the Simulation Rate Control block. Typically, a
Simulink simulation executes in a free-running loop whose speed depends on complexity of the model
and computer speed (see “Simulation Loop Phase” (Simulink)). The Simulation Rate Control block
attempts to regulate Simulink execution so that each update takes 0.02 seconds in wall-clock time
when possible. (This is equal to the fundamental sample time of the model.) See the comments inside
the block for more information.
In addition, the Enabled subsystems for the Proportional Controller and the Command Velocity
Publisher ensure that the model only reacts to genuinely new messages. If enabled subsystems were
not used, the model would repeatedly process the same (most-recently received) message repeatedly,
leading to wasteful processing and redundant publishing of command messages.
1-150
Fusion of Radar and Lidar Data Using ROS
Perform track-level sensor fusion on recorded lidar sensor data for a driving scenario recorded on a
rosbag. This example uses the same driving scenario and sensor fusion as the “Track-Level Fusion of
Radar and Lidar Data” (Sensor Fusion and Tracking Toolbox) example, but uses a prerecorded rosbag
instead of the driving scenario simulation.
This provides an example rosbag containing lidar, radar, and vehicle data, and is approximately 33MB
in size. Download the rosbag from the MathWorks website.
bagFile = matlab.internal.examples.downloadSupportFile("ros","rosbags/simulated_lidar_radar_drivi
bag = rosbag(bagFile);
disp(bag.AvailableTopics(:,["NumMessages", "MessageType"]))
NumMessages MessageType
___________ ________________________________________
The ego vehicle has one lidar and four radar sensors, as well as absolute positional information for
itself. These messages can be extracted into separate arrays for later fusion. Because this rosbag is
compressed to reduce file size, reading the messages may take a few seconds. Extract the messages
as structures using the DataFormat name-value argument, which improves overall performance for
ROS messages.
lidarBagSel = select(bag,"Topic","/ego/lidar_scan");
lidarMsgs = readMessages(lidarBagSel,"DataFormat","struct");
stateBagSel = select(bag,"Topic","/ego/state");
stateMsgs = readMessages(stateBagSel,"DataFormat","struct");
radarMsgs = cell(bag.AvailableTopics{"/ego/radar_1/detections","NumMessages"},4);
for idxRadar = 1:4
radarBagSel = select(bag,"Topic",sprintf("/ego/radar_%d/detections",idxRadar));
radarMsgs(:,idxRadar) = readMessages(radarBagSel,"DataFormat","struct");
end
Make timestamps to be used with fusion relative to the first message timestamp. Note that the bag
StartTime cannot be used since that is the timestamp the first message was recorded at, which is
later than the message timestamp.
clockBagSel = select(bag,"Topic","/clock");
clockMsg = readMessages(bag,1,"DataFormat","struct");
startTime = double(clockMsg{1}.Clock_.Sec) + double(clockMsg{1}.Clock_.Nsec)*1e-9;
1-151
1 ROS Featured Examples
Information about the sensors is known based on the vehicle set up, and needs to be put in a format
usable by the tracking algorithm.
Radar and lidar tracking algorithms are necessary to process the high-resolution scans and
determine the objects viewed in the scans without repeats. These algorithms are defined as helper
functions. More details on the algorithms can be seen in the “Track-Level Fusion of Radar and Lidar
Data” (Sensor Fusion and Tracking Toolbox) example.
radarTrackingAlgorithm = helperROSRadarTracker(radarInfo);
radarConfig = fuserSourceConfiguration("SourceIndex",1,...
"IsInitializingCentralTracks",true,...
"CentralToLocalTransformFcn",@central2radar,...
"LocalToCentralTransformFcn",@radar2central);
lidarTrackingAlgorithm = helperLidarTrackingAlgorithm(lidarInfo);
lidarConfig = fuserSourceConfiguration("SourceIndex",2,...
"IsInitializingCentralTracks",true);
fuser = trackFuser("SourceConfigurations",{radarConfig;lidarConfig},...
"StateTransitionFcn",lidarTrackingAlgorithm.StateTransitionFcn,...
"ProcessNoise",diag([1 3 1]),...
"HasAdditiveProcessNoise",false,...
"AssignmentThreshold",[250 inf],...
"ConfirmationThreshold",[3 5],...
"DeletionThreshold",[5 5],...
"StateFusion","Custom",...
"CustomStateFusionFcn",@helperRadarLidarFusionFcn);
Visualization
Set up figure and properties for visualization of sensor data using a helper function.
displayHelper = helperROSSensorFusionDisplay;
Iterate through the messages and run the sensor fusion algorithm. Watch the visualization to see the
rosbag played back and the tracking of vehicles using the sensor fusion.
The sensors were triggered to all measure simulataneously, and all radar sensors published a
message at each triggering, even if no detections were present. Because all the message arrays are
all the same length, the processing of the sensor data is far simpler. If sensors triggered at distinct
rates, connection issue occurred, or messages were received out of order, an intermediate step of
synchronizing the sensor data may be necessary.
1-152
Fusion of Radar and Lidar Data Using ROS
double(radarTimeStamp.Nsec)*1e-9 - startTime;
% Generate sensor tracks and analysis information like the bounding box
% detections and point cloud segmentation information.
radarTracks = radarTrackingAlgorithm(egoPose, radarDetections, radarTime);
[lidarTracks, lidarDetections, segmentationInfo] = ...
lidarTrackingAlgorithm(egoPose, ptCloud, lidarTime);
localTracks = [radarTracks ; lidarTracks];
1-153
1 ROS Featured Examples
% Update the fuser. The first call must contain one local track.
if ~(isempty(localTracks) && ~isLocked(fuser))
fusedTracks = fuser(localTracks,lidarTime);
else
fusedTracks = objectTrack.empty(0,1);
end
Utility Functions
radar2central
1-154
Fusion of Radar and Lidar Data Using ROS
xRadar = radarTrack.State;
PRadar = radarTrack.StateCovariance;
central2radar
xCentral = centralTrack.State;
PCentral = centralTrack.StateCovariance;
syncTrack
1-155
1 ROS Featured Examples
notState = ~strcmpi(props,'State');
notCov = ~strcmpi(props,'StateCovariance');
1-156
MATLAB Programming for Code Generation
This example shows the recommended workflow for generating a standalone executable from
MATLAB® code that contains ROS interfaces.
Prerequisites
Overview
A subset of ROS MATLAB functions such as rossubscriber, rospublisher, and rosrate support
C++ code generation. To create a standalone ROS node from MATLAB code, follow these steps:
• Create the entry-point function for creating a standalone application. The entry-point function
must not have any inputs and must not return any outputs.
• Add the %#codegen directive to the MATLAB function to indicate that it is intended for code
generation. This directive also enables the MATLAB code analyzer to identify warnings and errors
specific to MATLAB for code generation.
• Modify the ROS functions to use message structures.
• Identify MATLAB code that does not support C++ code generation and modify the MATLAB code
to use functions or constructs that support code generation.
• Create a MATLAB Coder configuration object and specify the hardware as 'Robot Operating
System (ROS)'.
• Use codegen command to generate a stand-alone executable.
function mynode(numIterations)
%mynode Receive and display sensor_msgs/JointState messages
rosinit;
% 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
1-157
1 ROS Featured Examples
This MATLAB code receives sensor_msgs/JointState messages published to the /servo topic
and displays the first element of the position in a loop. The function has an input argument that sets
the number of iterations. To create a stand-alone ROS node, modify the code as follows:
Note that you execute the rosinit and rosshutdown functions only once in a MATLAB session. Avoid
rosinit and rosshutdown functions for code intended for standalone deployment. In stand-alone
deployment, individual ROS nodes are not expected to start or stop the ROS master. If you need to
include rosinit and roshutdown calls in your MATLAB code for interpreted execution, declare
them as coder.extrinsic (MATLAB Coder) functions at the top of your entry-point function.
The entry-point function cannot take any inputs or return outputs. A standalone ROS node executable
is intended to be launched outside MATLAB, such as from a system command terminal, and therefore
cannot take any MATLAB inputs or return MATLAB outputs.
To eliminate the input argument numIterations, replace the for loop with an infinite while loop.
For stand-alone deployment, the generated node is expected to run until you terminate it externally. A
good programming practice is to replace the for loops with a while loop for standalone deployment.
The rossubscriber function needs the message type to be specified as a compile time constant for
code generation. The function uses this information to create the return message type for receive
calls. The rossubscriber function supports code generation for message structures only. To return
a message structure, specify the name-value pair argument, "DataFormat","struct", when
creating a subscriber.
After you modify the code, the MATLAB code for the entry-point function is as follows:
function mynode
%mynode Receive and display sensor_msgs/JointState messages
%#codegen
% 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
Create a MATLAB Coder configuration that uses "Robot Operating System (ROS)" hardware.
Set the HardwareImplementation.ProdHWDeviceType parameter of the MATLAB Coder
configuration object for the intended deployment hardware. For example, if you are deploying
1-158
MATLAB Programming for Code Generation
You can send messages to mynode using the following command on a ROS terminal:
rostopic pub /servo sensor_msgs/JointState -r 1 "{header:{seq: 0, stamp:{secs: 0,nsecs: 0},frame_
% 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
The message can accommodate multiple joints and multiple trajectory points. If the number of joints
is M and the number of trajectory points for each joint is N, trajMsg has the dimensions M-by-1 and
trajMsg.Positions has the dimensions N-by-1. For this example, publish two trajectory points per
joint.
The function has an input argument that sets the number of iterations. To create a stand-alone ROS
node, modify the code as follows:
1-159
1 ROS Featured Examples
• Eliminate the input argument updateRate by directly specifying it within function body.
• Add the %#codegen directive.
• Use message structures instead of message classes.
• Eliminate any message fields that use cell strings to prepare for code generation.
• Grow variable-size fields of message structures in the correct dimension.
To eliminate the input argument updateRate, specify the update rate using a constant literal in the
entry-point function body. To modify the updateRate, you must re-generate code from the entry-
point function.
Modify the rospublisher, rosmessage and rosrate functions to use message structures. The
trajectory_msgs/JointTrajectory message structure has a field, JointNames, which is of type
cell string. Message fields of this type are not supported for code generation due to MATLAB Coder
limitations. In order to generate code for mypubnode function, avoid the use of JointNames fields in
code generation using coder.target (MATLAB Coder) function.
The original mypubnode function grows variable-size fields of the message structs in the wrong
dimension. As an illustration, create a message of type trajectory_msgs/JointTrajectory at
the MATLAB command line. Note that the first dimension of the variable-size fields is of size 0 while
the second dimension is of size 1:
msg = rosmessage('trajectory_msgs/JointTrajectory')
msg =
MessageType: 'trajectory_msgs/JointTrajectory'
Header: [1×1 Header]
Points: [0×1 JointTrajectoryPoint]
JointNames: {0×1 cell}
The fields with dimensions 0-by-1 grow in the first dimension. The original code grows the Points
and Positions fields in the second dimension, which works in interpreted mode, but is not
supported for code generation. You get the following error message if you attempt to grow variable-
size fields of a message structure in the wrong dimension:
After you modify the code, the MATLAB code for the entry-point function is as follows:
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)
1-160
MATLAB Programming for Code Generation
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
Create a MATLAB Coder configuration that uses "Robot Operating System (ROS)" hardware.
Set the HardwareImplementation.ProdHWDeviceType parameter of the MATLAB Coder
configuration object for the intended deployment hardware. For example, if you are deploying
generated code to a Windows computer set HardwareImplementation.ProdHWDeviceType to
"Intel->x86-64 (Windows64)". To generate code execute the following commands:
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 ty
codegen mypubnode -config cfg
You can examine the contents of the messages published by mypubnode using rostopic echo /
traj command on a ROS terminal.
Additional Considerations
Code generation for messages containing cell strings: MATLAB Coder does not support code
generation for cell strings. You can send and receive ROS messages containing cell strings using
rossubsriber and rospublisher, but you cannot access the fields that are of type cell string. For
instance, in a sensor_msgs/JointState message, you cannot read or write to the field, Name,
which is of type cell string in MATLAB representation.
Variable-size message fields: Do not use indexing past the array dimension pattern to grow the size
of variable-size arrays in message fields. Use the following form:
msg = rosmessage('sensor_msgs/JointState','DataFormat','struct');
msg.Position = [0.1; -0.1];
...
msg.Position = [msg.Position; 0.2]; % Add new data point
For more information, see “Incompatibilities with MATLAB in Variable-Size Support for Code
Generation” (MATLAB Coder). Also, for the MATLAB Coder configuration object, you must set
1-161
1 ROS Featured Examples
EnableVariableSizing property to true and enable dynamic memory allocation for variable-size
arrays.
See Also
Related Examples
• “Generate a Standalone ROS Node” on page 1-163
1-162
Generate a Standalone ROS Node
This example shows how to generate C++ code for a standalone ROS node from a MATLAB function.
It then shows how to build and run the ROS node on a Windows® machine.
Prerequisites
Copy the robotROSFeedbackControl function to your local directory and change the
defaultDesiredPos variable to the desired coordinates.
Start an a Gazebo Empty World from the Linux virtual machine by opening the Gazebo Empty
application on the desktop. In the Linux virtual machine for ROS Toolbox, the robot is located at the
[0,0] location by default.
Create a rosdevice object specifying the deviceAddress, username, and password values of
the Virtual Machine running Gazebo. This establishes an SSH connection between the ROS device
and MATLAB.
gazeboVMDevice = rosdevice('172.18.250.139','user','password');
Create a MATLAB ROS node in the same ROS network as the virtual machine. See the list of available
ROS nodes.
rosinit(gazeboVMDevice.DeviceAddress,11311)
rosnode list
/gazebo
/gazebo_gui
/matlab_global_node_38424
/rosout
Run the controller and observe that the robot is moving towards the published destination. At the
same time, observe the trajectory of the robot that shows up in a MATLAB figure. Keep this figure
open to compare the behavior of MATLAB execution and the generated executable node.
robotROSFeedbackControl
1-163
1 ROS Featured Examples
You can change the desired destination while the robot is moving. To do so, open a new terminal from
the virtual machine, source the ROS repository, and publish the new destination coordinates in the
form of a std_msgs/Float64MultiArray message to the /dest topic.
~$ source /opt/ros/noetic/local_setup.bash
~$ rostopic pub -1 /dest std_msgs/Float64MultiArray "{data:[0,0]}"
You can also tweak the distanceThre, linearVelocity, and rotationGain values in
robotROSFeedbackControl.m to obtain the desired robot behavior. For the proportional controller
in this example, the following parameter ranges provide robust performance. Alternatively, you can
replace the proportional controller with a custom controller for performance comparison. To observe
the behavior, reset the robot on the virtual machine by pressing Ctrl-R in Gazebo.
distanceThre: 0<x<1
linearVelocity: 0<x<3
rotationGain: 0<x<6
The controller loop will terminate after the goal is reached, if more than 40 seconds has elapsed since
the start time. Alternatively, you can terminate the controller any time using Ctrl-C or typing in the
1-164
Generate a Standalone ROS Node
following command in the terminal from the virtual machine. Note that if you open a new terminal in
the virtual machine, you must source the ROS repository.
~$ rostopic pub -1 /stop std_msgs/Bool "1"
To generate a standalone C++ node, modify the function to make it compatible for code generation.
• Because objects do not support code generation, replace them with structs for rospublisher,
rossubscriber, and rosmessage. Specify the name-value pair "DataFormat","struct" in
the respective function calls to create them as structures.
• Save the modified MATLAB function to robotROSFeedbackControlCodegen.m. Ensure any
other modifications that you made in robotROSFeedbackControl function are reflected in
robotROSFeedbackControlCodegen.
Reset the Gazebo scene after simulation using the /gazebo/reset_simulation service. Create a
rossvcclient object for the service and use the call object function to call the service and reset
the Gazebo simulation scene.
gazeboResetClient = rossvcclient('/gazebo/reset_simulation','DataFormat','struct');
call(gazeboResetClient);
1-165
1 ROS Featured Examples
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- ~~ traversing 41 packages in topological order:
-- ~~ - husky_desktop (metapackage)
-- ~~ - husky_simulator (metapackage)
-- ~~ - kortex_move_it_config (metapackage)
-- ~~ - mav_comm (metapackage)
-- ~~ - rotors_description
-- ~~ - rotors_simulator (metapackage)
-- ~~ - husky_msgs
-- ~~ - mav_state_machine_msgs
-- ~~ - mav_system_msgs
-- ~~ - rotors_comm
-- ~~ - mav_msgs
-- ~~ - robotrosfeedbackcontrolcodegen
-- ~~ - husky_control
-- ~~ - husky_description
-- ~~ - husky_gazebo
-- ~~ - husky_navigation
-- ~~ - husky_viz
-- ~~ - kortex_control
-- ~~ - kortex_description
-- ~~ - kortex_gazebo
-- ~~ - rotors_evaluation
-- ~~ - rqt_rotors
-- ~~ - mav_planning_msgs
-- ~~ - opencv_node
-- ~~ - rotors_control
-- ~~ - rotors_hil_interface
-- ~~ - rotors_joy_interface
-- ~~ - gazebo_version_helpers
-- ~~ - gazebo_grasp_plugin
-- ~~ - roboticsgroup_upatras_gazebo_plugins
-- ~~ - rotors_gazebo_plugins
-- ~~ - kortex_driver
-- ~~ - gen3_lite_gen3_lite_2f_move_it_config
-- ~~ - gen3_move_it_config
-- ~~ - gen3_robotiq_2f_140_move_it_config
-- ~~ - gen3_robotiq_2f_85_move_it_config
-- ~~ - kortex_examples
-- ~~ - kortex_gazebo_camera
-- ~~ - kortex_gazebo_depth
-- ~~ - rotors_gazebo
1-166
Generate a Standalone ROS Node
-- ~~ - mw_vision_example
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- +++ processing catkin metapackage: 'husky_desktop'
-- ==> add_subdirectory(husky/husky_desktop)
-- +++ processing catkin metapackage: 'husky_simulator'
-- ==> add_subdirectory(husky/husky_simulator)
-- +++ processing catkin metapackage: 'kortex_move_it_config'
-- ==> add_subdirectory(ros_kortex/kortex_move_it_config/kortex_move_it_config)
-- +++ processing catkin metapackage: 'mav_comm'
-- ==> add_subdirectory(mav_comm/mav_comm)
-- +++ processing catkin package: 'rotors_description'
-- ==> add_subdirectory(rotors_simulator/rotors_description)
1-167
1 ROS Featured Examples
-- Found DART: /usr/include (Required is at least version "6.6") found components: dart
-- Found Protobuf: /usr/lib/x86_64-linux-gnu/libprotobuf.so;-lpthread (found version "3.6.1")
-- Looking for ignition-math6 -- found version 6.8.0
-- Searching for dependencies of ignition-math6
-- Looking for OGRE...
-- Found Ogre Ghadamon (1.9.0)
-- Found OGRE: optimized;/usr/lib/x86_64-linux-gnu/libOgreMain.so;debug;/usr/lib/x86_64-linux-gnu
-- Looking for OGRE_Paging...
-- Found OGRE_Paging: optimized;/usr/lib/x86_64-linux-gnu/libOgrePaging.so;debug;/usr/lib/x86_64-
-- Looking for OGRE_Terrain...
-- Found OGRE_Terrain: optimized;/usr/lib/x86_64-linux-gnu/libOgreTerrain.so;debug;/usr/lib/x86_6
-- Looking for OGRE_Property...
-- Found OGRE_Property: optimized;/usr/lib/x86_64-linux-gnu/libOgreProperty.so;debug;/usr/lib/x86
-- Looking for OGRE_RTShaderSystem...
-- Found OGRE_RTShaderSystem: optimized;/usr/lib/x86_64-linux-gnu/libOgreRTShaderSystem.so;debug;
-- Looking for OGRE_Volume...
-- Found OGRE_Volume: optimized;/usr/lib/x86_64-linux-gnu/libOgreVolume.so;debug;/usr/lib/x86_64-
-- Looking for OGRE_Overlay...
-- Found OGRE_Overlay: optimized;/usr/lib/x86_64-linux-gnu/libOgreOverlay.so;debug;/usr/lib/x86_6
-- Looking for ignition-math6 -- found version 6.8.0
-- Looking for ignition-transport8 -- found version 8.2.0
-- Searching for dependencies of ignition-transport8
1-168
Generate a Standalone ROS Node
1-169
1 ROS Featured Examples
1-170
Generate a Standalone ROS Node
-- Found DART: /usr/include (Required is at least version "6.6") found components: dart
-- Found Protobuf: /usr/lib/x86_64-linux-gnu/libprotobuf.so;-lpthread (found version "3.6.1")
-- Looking for ignition-math6 -- found version 6.8.0
-- Searching for dependencies of ignition-math6
-- Looking for OGRE...
-- Found Ogre Ghadamon (1.9.0)
-- Found OGRE: optimized;/usr/lib/x86_64-linux-gnu/libOgreMain.so;debug;/usr/lib/x86_64-linux-gnu
-- Looking for OGRE_Paging...
-- Found OGRE_Paging: optimized;/usr/lib/x86_64-linux-gnu/libOgrePaging.so;debug;/usr/lib/x86_64-
-- Looking for OGRE_Terrain...
-- Found OGRE_Terrain: optimized;/usr/lib/x86_64-linux-gnu/libOgreTerrain.so;debug;/usr/lib/x86_6
-- Looking for OGRE_Property...
1-171
1 ROS Featured Examples
1-172
Generate a Standalone ROS Node
1-173
1 ROS Featured Examples
-- GAZEBO 11.5.1
--
-- BUILD_MAVLINK_INTERFACE_PLUGIN = FALSE, NOT adding mavros dependency and NOT building mavlink_
-- CMAKE_INSTALL_PREFIX = /home/user/catkin_ws/install
-- +++ processing catkin package: 'kortex_driver'
-- ==> add_subdirectory(ros_kortex/kortex_driver)
CONAN_TARGET_PLATFORM is x86
-- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy
1-174
Generate a Standalone ROS Node
1-175
1 ROS Featured Examples
-- Generating done
1-176
Generate a Standalone ROS Node
1-177
1 ROS Featured Examples
1-178
Generate a Standalone ROS Node
---
Running ROS node.
---
The node will connect to the ROS master at 'http://172.18.250.139:11311' and advertise its addres
Use the 'rosdevice' object to stop the node or restart it with different settings.
Code generation successful.
Reset the Gazebo scene and call plotPath to plot the robot trajectory.
call(gazeboResetClient);
plotPath
1-179
1 ROS Featured Examples
The configuration generates and runs the ROS node on your remote device. You can opt to deploy and
run the ROS node on the local machine by modifying the coder configuration object, cfg.
cfg = coder.config('exe');
cfg.Hardware = coder.hardware('Robot Operating System (ROS)');
cfg.Hardware.BuildAction = 'Build and run';
cfg.Hardware.DeployTo = 'Localhost';
codegen robotROSFeedbackControlCodegen -args {} -config cfg
plotPath
After the generated executable starts running, for the same destination coordinates, verify that the
trajectory of the robot is similar to what you observe during MATLAB execution. You can also observe
the robot moving in Gazebo on the virtual machine. You can publish a different destination coordinate
while the robot is in motion. Refer to the Control a ROS-Enabled Robot with a Function on page 1-163
section, which shows how to publish a new set of destination coordinates through a virtual machine
terminal.
1-180
Generate a Standalone ROS Node
Terminate the generated ROS node by using the stopNode function of the rosDevice object.
Alternatively, you can terminate the execution by pressing Ctrl-C or sending a message to the /stop
topic. Reset the Gazebo scene.
stopNode(gazeboVMDevice,'robotROSFeedbackControlCodegen')
call(gazeboResetClient);
rosshutdown
See Also
Related Examples
• “MATLAB Programming for Code Generation” on page 1-157
1-181
1 ROS Featured Examples
This example shows how to use MATLAB® code generation to create a ROS node to move an
unmanned aerial vehicle (UAV) along a predefined circular path and a set of specified custom
waypoints.
In this example, you deploy a MATLAB function as a standalone ROS node to control a simulated
PX4® UAV with Gazebo. For more information on ROS node generation from MATLAB code, see
“MATLAB Programming for Code Generation” on page 1-157.
Download a virtual machine using instructions in “Get Started with Gazebo and Simulated TurtleBot”
on page 1-205.
1-182
Generate ROS Node for UAV Waypoint Follower
• Specify the IP address and port number of the ROS master in Gazebo so that MATLAB® can
communicate with the PX4 simulator. For this example, the ROS master in Gazebo is http://
192.168.192.136:11311 and your host computer address is 192.168.31.1.
• Start the ROS network using rosinit.
ipaddress = '192.168.93.136';
%Shut down global node if one is already running
rosshutdown();
rosinit(ipaddress,11311);
1-183
1 ROS Featured Examples
View the ROS topics available on the network. Verify that the topics with the namespace /mavros are
available.
rostopic("list");
/clock
/diagnostics
/gazebo/link_states
/gazebo/model_states
/gazebo/parameter_descriptions
/gazebo/parameter_updates
/gazebo/set_link_state
/gazebo/set_model_state
/mavlink/from
/mavlink/gcs_ip
/mavlink/to
/mavros/actuator_control
/mavros/adsb/send
/mavros/adsb/vehicle
/mavros/altitude
/mavros/battery
/mavros/cam_imu_sync/cam_imu_stamp
/mavros/companion_process/status
/mavros/debug_value/debug
/mavros/debug_value/debug_vector
/mavros/debug_value/named_value_float
/mavros/debug_value/named_value_int
/mavros/debug_value/send
/mavros/esc_info
/mavros/esc_status
/mavros/estimator_status
/mavros/extended_state
/mavros/fake_gps/mocap/tf
/mavros/geofence/waypoints
/mavros/global_position/compass_hdg
/mavros/global_position/global
/mavros/global_position/gp_lp_offset
/mavros/global_position/gp_origin
/mavros/global_position/home
/mavros/global_position/local
/mavros/global_position/raw/fix
/mavros/global_position/raw/gps_vel
/mavros/global_position/raw/satellites
/mavros/global_position/rel_alt
/mavros/global_position/set_gp_origin
/mavros/gps_rtk/rtk_baseline
/mavros/gps_rtk/send_rtcm
/mavros/gpsstatus/gps1/raw
/mavros/gpsstatus/gps1/rtk
/mavros/gpsstatus/gps2/raw
/mavros/gpsstatus/gps2/rtk
/mavros/hil/actuator_controls
/mavros/hil/controls
/mavros/hil/gps
/mavros/hil/imu_ned
/mavros/hil/optical_flow
/mavros/hil/rc_inputs
/mavros/hil/state
1-184
Generate ROS Node for UAV Waypoint Follower
/mavros/home_position/home
/mavros/home_position/set
/mavros/imu/data
/mavros/imu/data_raw
/mavros/imu/diff_pressure
/mavros/imu/mag
/mavros/imu/static_pressure
/mavros/imu/temperature_baro
/mavros/imu/temperature_imu
/mavros/landing_target/lt_marker
/mavros/landing_target/pose
/mavros/landing_target/pose_in
/mavros/local_position/accel
/mavros/local_position/odom
/mavros/local_position/pose
/mavros/local_position/pose_cov
/mavros/local_position/velocity_body
/mavros/local_position/velocity_body_cov
/mavros/local_position/velocity_local
/mavros/log_transfer/raw/log_data
/mavros/log_transfer/raw/log_entry
/mavros/manual_control/control
/mavros/manual_control/send
/mavros/mission/reached
/mavros/mission/waypoints
/mavros/mocap/pose
/mavros/mount_control/command
/mavros/mount_control/orientation
/mavros/obstacle/send
/mavros/odometry/in
/mavros/odometry/out
/mavros/onboard_computer/status
/mavros/param/param_value
/mavros/play_tune
/mavros/px4flow/ground_distance
/mavros/px4flow/raw/optical_flow_rad
/mavros/px4flow/raw/send
/mavros/px4flow/temperature
/mavros/radio_status
/mavros/rallypoint/waypoints
/mavros/rc/in
/mavros/rc/out
/mavros/rc/override
/mavros/setpoint_accel/accel
/mavros/setpoint_attitude/cmd_vel
/mavros/setpoint_attitude/thrust
/mavros/setpoint_position/global
/mavros/setpoint_position/global_to_local
/mavros/setpoint_position/local
/mavros/setpoint_raw/attitude
/mavros/setpoint_raw/global
/mavros/setpoint_raw/local
/mavros/setpoint_raw/target_attitude
/mavros/setpoint_raw/target_global
/mavros/setpoint_raw/target_local
/mavros/setpoint_trajectory/desired
/mavros/setpoint_trajectory/local
/mavros/setpoint_velocity/cmd_vel
1-185
1 ROS Featured Examples
/mavros/setpoint_velocity/cmd_vel_unstamped
/mavros/state
/mavros/statustext/recv
/mavros/statustext/send
/mavros/target_actuator_control
/mavros/time_reference
/mavros/timesync_status
/mavros/trajectory/desired
/mavros/trajectory/generated
/mavros/trajectory/path
/mavros/vfr_hud
/mavros/vision_pose/pose
/mavros/vision_pose/pose_cov
/mavros/vision_speed/speed_twist_cov
/mavros/wind_estimation
/rosout
/rosout_agg
/tf
/tf_static
This example uses MAVROS to control the PX4 drone using the mavros_msgs package.
msgs = rosmsg("list");
mavrosMsgs = msgs(startsWith(msgs,"mavros_msgs"))
1-186
Generate ROS Node for UAV Waypoint Follower
{'mavros_msgs/ESCStatusItem' }
{'mavros_msgs/EstimatorStatus' }
⋮
Declare all the required ROS publishers, subscribers, and service clients to communicate over
MAVROS.
stateSub = rossubscriber("/mavros/state","mavros_msgs/State","DataFormat","struct");
% Create a SetMode service client
setModeCli = rossvcclient("/mavros/set_mode","mavros_msgs/SetMode","DataFormat","struct");
% Create a arm command service client
armingCli = rossvcclient("/mavros/cmd/arming","mavros_msgs/CommandBool","DataFormat","struct");
% Subscribe to landing message
landNowSub = rossubscriber("/land_message","std_msgs/Bool","DataFormat","struct");
% Subscribe to current position of PX4
currPosSub = rossubscriber("/mavros/local_position/pose","geometry_msgs/PoseStamped","DataFormat"
% Create a publisher for PX4 position command
posePub = rospublisher("/mavros/setpoint_position/local","geometry_msgs/PoseStamped","DataFormat"
poseMsg = rosmessage(posePub);
if isempty(coder.target)
figure("Name","Circular trajectory");
plot3(xpoints,ypoints,altitude*ones(1,numPoints));
grid on;
end
1-187
1 ROS Featured Examples
The rate with which the topic is published is controlled by the rosrate function. For this example,
set the rate to 20 Hz.
In px4sitlCircularLoop function, the control loop initializes the takeoff sequence by changing the
mode and arming PX4. If the PX4 is ready to accept commands, this function returns immediately.
exampleHelperUAVTakeOff(stateSub,setModeCli,armingCli,5.0);
The control loop sets the X and Y fields of the pose message of type geometry_msgs/PoseStamped
and sends the message over the /mavros/setpoint_position/local topic. The altitude is
maintained at 2 meters.
In MATLAB, the control loop exits after PX4 follows the circular path three times.
In C++ ROS node deployed from px4sitlCircularLoop function, the control loop subscribes to
the /land_message topic of type std_msgs/Bool and exits when the message value is set to true.
After exiting the control loop, the function runs the landing sequence.
1-188
Generate ROS Node for UAV Waypoint Follower
Landing Sequence
During landing, the MATLAB function calculates the waypoints from current position on the circular
path back to the origin. The PX4 follows the waypoints to reach the origin position while maintaining
the altitude. After it reaches the origin, the exampleHelperUAVLand function lands the PX4.
exampleHelperUAVLand(posePub,poseMsg,r);
Landed successfully
Before deploying the node on the VM, create a Catkin workspace folder by running the following
commands in MATLAB.
vmdev = rosdevice(ipaddress,'user','password');
vmdev.CatkinWorkspace = '/tmp/px4stil_catkinws';
system(vmdev,['mkdir -p ', vmdev.CatkinWorkspace, '/src; source /opt/ros/noetic/setup.bash; cd ',
ans =
Hardware with properties:
1-189
1 ROS Featured Examples
The generated node starts running on the ROS device. You can verify this by using the rosdevice
object.
isNodeRunning(vmdev,"px4sitlCircularLoop")
Simulated PX4 takes off and starts flying in a circular pattern in Gazebo.
Stop the ROS node by sending the landing message from MATLAB.
pubLandMsg = rospublisher("/land_message","DataFormat","struct")
pubLandMsg =
Publisher with properties:
1-190
Generate ROS Node for UAV Waypoint Follower
TopicName: '/land_message'
NumSubscribers: 1
IsLatching: 1
MessageType: 'std_msgs/Bool'
DataFormat: 'struct'
msg = rosmessage(pubLandMsg);
msg.Data = true;
send(pubLandMsg,msg);
Similar to the px4sitlCircularLoop function, this function also has three sections: the
initialization sequence, the trajectory follower controller loop that moves the PX4 along the desired
waypoints, and the landing sequence.
It uses minsnappolytraj (Robotics System Toolbox) to return an array with the position, velocity,
and acceleration at various points along the trajectory.
latlonpoints = [latlonhome;
42.301389286674166 -71.37609390148994 10;
42.302289545648726 -71.376093901489938 10;
42.302289539236234 -71.374881155270842 10;
42.301389280261866 -71.374881172546949 10;
42.301389286674166 -71.37609390148994 10];
timeOfFlight = 100; % seconds
sampleSize = 100; % samples per segment
[q,qd,qdd] = exampleHelperCreateReferencePath(latlonhome,latlonpoints,timeOfFlight,sampleSize);
1-191
1 ROS Featured Examples
Note the precision of the latitude and longitude values. If you modify the function to use a different
set of waypoints, you must provide waypoints with similar precision.
The control loop starts with the takeoff sequence using exampleHelperUAVTakeOff helper
function.
The control loop calls the exampleHelperTrajectoryController function, which accepts the
current position and velocity values, the reference position, reference velocity, and reference
accelerations generated by the exampleHelperCreateReferencePath function, and the PD
(proportional-derivative) gain values and returns the desired acceleration values along the X, Y and Z
axes.
accCMD = 3×1
0.0195
-0.1541
0.1840
The control loop converts these acceleration values into the acceleration message of type
geometry_msgs/Vector3Stamped, and sends the message over the /mavros/setpoint_accel/
accel topic.
1-192
Generate ROS Node for UAV Waypoint Follower
The control loop tracks the index of the trajectory segments and the proximity to the final waypoint.
The control loop exits once the PX4 reaches within 1 meter radius of the final waypoint.
Deploy the MATLAB function as a standalone ROS node using the codegen command:
codegen("px4sitlWaypointFollower","-config",cfg);
Observe the PX4 SITL in Gazebo. Once the node starts running, the PX4 UAV takes off and starts
following the waypoints.
The deployed ROS node stops once it reaches the final waypoint.
1-193
1 ROS Featured Examples
This example shows you how to generate and build a standalone ROS node from a Simulink® model.
Introduction
In this example, you configure a model to generate C++ code for a standalone ROS node. You then
build and run the ROS node on an Ubuntu® Linux® system.
Prerequisites
Configure a model to generate C++ code for a standalone ROS node. The model is the proportional
controller introduced in the “Feedback Control of a ROS-Enabled Robot” on page 1-148 example.
• Open RobotController.slx. Click the link or run RobotController in the Command Window.
• In the Prepare section under ROS tab, click Hardware Settings to open the Hardware
Implementation pane of the Configuration Parameters dialog. The Hardware board settings
section contains settings specific to the generated ROS package, such as information to be
included in the package.xml file. Change Maintainer name to ROS Example User.
• The model uses variable-sized arrays. If you have Embedded Coder™ installed, you must enable
code-generation for variable-sized signals. Check variable-size signals under Code Generation
> Interface > Software environment. If the variable-size signals option is not visible, check
the option, Use Embedded Coder Features in Hardware Implementation > Advanced
parameters.
• In the Solver pane of the Configuration Parameters dialog, ensure that Solver Type is set to
Fixed-step, and set Fixed-step size to 0.05. In generated code, the Fixed-step size defines the
actual time step, in seconds, that is used for the model update loop (see “Execution of Code
Generated from a Model” (Simulink Coder)). It can be made smaller (e.g., 0.001 or 0.0001) but for
current purposes 0.05 is sufficient.
A ROS device is any Linux system that has ROS installed and is capable of building and running a
ROS node. If you have Simulink Coder, you can generate code for a standalone ROS node. If your
system is connected to a ROS device, Simulink can also transfer the generated code to the ROS
device, build an executable, and run the resulting ROS node (this is referred to as "deploying" the
ROS node).
In this task, you decide if you want to generate code for the ROS node or if you want to build and run
it on a ROS device. If you are connected to a ROS device, you can configure Simulink to use it as a
deployment target for your ROS node.
1-194
Generate a Standalone ROS Node from Simulink
ROS Folder is the location of the ROS installation on the ROS device. If you do not specify this folder,
the settings test (see next step) tries to determine the correct folder for you.
• If the ROS device is turned on and accessible from your computer, you can verify the connection
settings by clicking Test. The test verifies every device setting and display warnings and errors in
the Simulink Diagnostic Viewer if problems are found. If possible, the test also suggests how the
problems can be fixed. Click Test now.
1-195
1 ROS Featured Examples
• Most likely, the Catkin workspace ~/catkin_ws_test does not exist on the target device. The
test detects this problem and suggests to create the folder and initialize the workspace. Click Fix
to apply this action automatically. After a few seconds, you should see a green notice that the
folder has been created successfully. In the following figure you can see an example of creating
the folder successfully. To verify that the Catkin workspace is now available, click Test in the
connection settings dialog again. The warning has disappeared and the Catkin workspace is ready
to build your ROS node.
• Change the device connection settings and test them until no other warnings or errors are shown.
If an automatic fix to your settings is possible, Simulink suggests it by displaying the Fix button.
Once you have a good set of settings, click OK in the connection settings dialog to save the
settings.
The connection settings are not specific to a single model, but apply to all ROS models in
Simulink.
Generate code for a standalone ROS node, and automatically transfer, build, and run it on the ROS
device. Exercise the generated ROS node using a ROS master running on the ROS device.
1. In MATLAB®, change the current folder to a temporary location where you have write permission.
2. The code generation process first prepares the model for simulation to ensure that all blocks are
properly initialized. This preparation requires a valid connection to a ROS master.
1-196
Generate a Standalone ROS Node from Simulink
In MATLAB, you can use the rosdevice object to start a ROS master on the ROS device. If you
provide no arguments, rosdevice uses the device connection settings you entered in the Simulink
dialog to connect to the ROS device.
d = rosdevice
runCore(d);
3. Use rosinit to connect MATLAB to the ROS master running on the ROS device:
rosinit(d.DeviceAddress)
4. Tell Simulink to use the same ROS connection settings as MATLAB. Under the Simulation tab, in
Prepare section, select ROS Network. Set the ROS Master (ROS 1) and Node Host network
addresses to Default.
1-197
1 ROS Featured Examples
You only have to execute steps 2 - 4 once per MATLAB session, not every time you generate
a ROS node.
5. Under the ROS tab, click Deploy > Build & Run. If you get any errors about bus type mismatch,
close the model, clear all variables from the base MATLAB workspace, and re-open the model.
1-198
Generate a Standalone ROS Node from Simulink
Click on the View Diagnostics link at the bottom of the model toolbar to see the output of the build
process.
6. Once the code generation completes, the ROS node is transferred to the Catkin workspace on your
ROS device. The node builds there and starts to run automatically in a synchronous fashion based on
the sample time of the model.
The generated node connects to the ROS master running on the ROS device.
7. Use rosnode to list all running nodes is the ROS network. "robotcontroller" should be in the
displayed list of nodes.
rosnode list
You can use rostopic to verify that the deployed node publishes data on the ROS topic to control
the robot motion:
Run the newly-built ROS node and verify its behavior using a MATLAB-based robot simulator.
sim = ExampleHelperSimulinkRobotROS
1-199
1 ROS Featured Examples
2. Verify that the simulated robot moves toward the goal (the Desired Position constant specified in
the model). The robot stops once it reaches the goal [-10, 10].
3. Click Reset Simulation to reset the robot's position to [0, 0]. The robot starts to move
immediately towards the goal position.
4. In MATLAB, you can manage ROS nodes generated by Simulink with the rosdevice object. Once
a Simulink model is deployed, you can use rosdevice to run and stop the node at any point, without
having to rebuild it in Simulink.
The AvailableNodes property shows the deployed robotcontroller node. You can verify that the
node is running by calling the isNodeRunning function.
d = rosdevice
1-200
Generate a Standalone ROS Node from Simulink
isNodeRunning(d, 'robotcontroller')
stopNode(d, 'robotcontroller')
isNodeRunning(d, 'robotcontroller')
6. Click the Reset Simulation button in the simulation window. The robot stays at location [0,0] and
does not move.
runNode(d, 'robotcontroller')
• The robot should start moving towards the goal position again.
7. Once you are done verifying, you can clean up the system state as follows.
stopNode(d, 'robotcontroller')
• On the host computer, close the Robot Simulator figure window and type rosshutdown at the
MATLAB command line.
rosshutdown
Specify code generation and build options: You can choose different code generation and build
behaviors by specifying one of these Deployment options from the toolstrip under ROS tab.
• Generate code — Generates the ROS package source code on localhost or remote device.
• Build Model — Generates the ROS package source code and builds the standalone executable on
localhost or remote device.
• Build & Run — Generates the ROS package source code, builds the standalone executable and
starts running it on localhost or remote device.
Specify ROS network settings in Simulink: By default, Simulink uses the ROS connection settings
from rosinit in MATLAB. To override these settings, specify ROS connection settings in Simulink.
1-201
1 ROS Featured Examples
Under the Simulation tab, in Prepare section, select ROS Network and set the ROS Master and
Node Host network addresses:
1-202
Generate a Standalone ROS Node from Simulink
Generated C++ code archive: No matter what Build action you select (None, Build and load,
Build and run), Simulink always generates two files in your current folder: an archive containing the
C++ source code (RobotController.tgz in our example) and a shell script for extracting and building
the C++ code manually (build_ros_model.sh). If your MATLAB computer is not connected to the ROS
device, you can transfer the files manually and build them there.
Processor-specific generated code: If you use blocks from other products (such as Computer
Vision System Toolbox™), the generated code may include processor-specific optimizations that lead
to compilation problems when building the ROS node on Linux. In these cases, you need to let
Simulink know the platform on which the generated code is compiled. You can do this through the
Hardware Implementation pane of the Model Configuration Parameters dialog.
Running ROS Master in MATLAB: In the example above, you connected to a ROS master running
on the ROS device. Alternatively, you can create a ROS master in MATLAB. Use rosinit at the
MATLAB command line:
rosinit('NodeHost', <IP address of your computer>)
For example, if the IP address of your host computer is 172.18.250.92, use the following command:
rosinit('NodeHost', '172.18.250.92')
The NodeHost setting is important to ensure that the generated ROS node is able to communicate to
the master on MATLAB. Note: The generated ROS node will use the NodeHost IP address to
communicate to the global ROS node in MATLAB, so ensure that the specified IP address is accessible
from the ROS device (for example, using ping). See the “Connect to a ROS Network” on page 1-45
example for more details on the significance of the NodeHost setting.
Tasking mode: Simulink can generate code for either multi-tasking or single-tasking modes (see
“Time-Based Scheduling and Code Generation” (Simulink Coder)). By default, generated ROS code
uses single-tasking mode (a single thread for all the rates) without real-time scheduling. This allows
the generated ROS code to execute without sudo privileges, but can lead to less predictable
performance.
If you require more predictable performance, you can configure the model to use multi-tasking. In the
Solver pane of the Configuration Parameters dialog enable Treat each discrete rate as a separate
task to enable multi-tasking. In generated code, this creates a separate thread for each rate in the
model and uses prioritized scheduling for the threads.
1-203
1 ROS Featured Examples
To run the ROS node, you need to have administrative privileges on the ROS device. Simulink
automatically detects if your privileges are insufficient when the model is deployed to the target
device.
See Also
Related Examples
• “Generate Code to Manually Deploy a ROS Node from Simulink” on page 6-30
1-204
Get Started with Gazebo and Simulated TurtleBot
This example shows how to set up the Gazebo® simulator engine. This example prepares you for
further exploration with Gazebo and also for exploration with a simulated TurtleBot®.
Gazebo is a simulator that allows you to test and experiment realistically with physical scenarios.
Gazebo is a useful tool in robotics because it allows you to create and run experiments rapidly with
solid physics and good graphics. MATLAB® connects to Gazebo through the ROS interface.
You can download a virtual machine image that already has ROS and Gazebo installed. This virtual
machine is based on Ubuntu® Linux® and is pre-configured to support the examples in ROS
Toolbox™.
1-205
1 ROS Featured Examples
1-206
Get Started with Gazebo and Simulated TurtleBot
Note: If the Gazebo screen looks entirely black, refresh the image by minimizing it and then
maximizing it.
1-207
1 ROS Featured Examples
• Two ROS environment variables must be set to set up the network: ROS_MASTER_URI and
ROS_IP. If you are using the demos from the desktop of the Linux® virtual machine, these
variables are usually automatically set at startup.
• (Optional) If you are using your own virtual machine set up the variables by executing the
following commands in the terminal. Replace IP_OF_VM with the IP address retrieved
through ifconfig:
• Check the environment variables using echo $ENV_VAR (replacing ENV_VAR with the
appropriate environment variable). You can close and reopen your terminal for it to take effect.
• The following diagram illustrates correct environment variable assignments (with fake IP
addresses)
1-208
Get Started with Gazebo and Simulated TurtleBot
If you already have Gazebo running on a Linux distribution, set up the simulator as described here:
1-209
1 ROS Featured Examples
• Find the IP address of your host computer on the network. On a Windows® machine, at the
command prompt, type ipconfig. On a Mac or Linux machine, open a terminal and type
ifconfig. An example of ipconfig is shown.
1-210
Get Started with Gazebo and Simulated TurtleBot
Note: The connection type can vary depending on how you are connected to the laptop. In this case
you use the Ethernet, however, in many cases the wireless (wlan) is the appropriate connection.
• Ping the simulator machine ping IP_OF_VM. A successful ping is shown first, followed by an
unsuccessful ping.
1-211
1 ROS Featured Examples
Next Steps
• For more Gazebo examples, refer to: “Pick-and-Place Workflow in Gazebo Using ROS” (Robotics
System Toolbox)
• For TurtleBot examples, refer to: “Communicate with the TurtleBot” on page 1-243
1-212
Add, Build, and Remove Objects in Gazebo
This example explores more in-depth interaction with the Gazebo® Simulator from MATLAB®. Topics
include creating simple models, adding links and joints to models, connecting models together, and
applying forces to bodies.
Prerequisites: “Get Started with Gazebo and Simulated TurtleBot” on page 1-205
Connect to Gazebo®
On your Linux® machine, start Gazebo. If you are using the virtual machine from “Get Started with
Gazebo and Simulated TurtleBot” on page 1-205, start the Gazebo Empty world from the desktop.
Initialize ROS by replacing ipaddress with the IP address of the virtual machine. Create an instance
of the ExampleHelperGazeboCommunicator class.
ipAddress = "http://192.168.93.144:11311";
rosinit(ipAddress)
gazebo = ExampleHelperGazeboCommunicator;
To create a model, use the ExampleHelperGazeboModel class. Define properties (using addLink)
and spawn a ball using the spawnModel function.
ball = ExampleHelperGazeboModel("Ball")
ball =
ExampleHelperGazeboModel with properties:
Name: 'Ball'
ModelObj: [1×1 matlab.io.xml.dom.Document]
Links: []
Joints: []
sphereLink =
'link0'
spawnModel(gazebo,ball,[8.5 0 1])
All units for Gazebo commands are specified in SI units. Depending on your view, you might have to
zoom out to see the ball, because it is placed at [8.5, 0, 1]. Here is an image of the scene:
1-213
1 ROS Featured Examples
Create vectors x and y for the location of the bowling pins (in meters).
x = [ 1.5 1.5 1.5 1.5 2.5 2.5 2.5 3.5 3.5 4.5];
y = [-1.5 -0.5 0.5 1.5 -1 0 1 -0.5 0.5 0];
Define a basic model for the bowling pin using the ExampleHelperGazeboModel object. Use
addLink to create the cylinder and the ball.
pin = ExampleHelperGazeboModel("BowlPin");
The output of addLink produces a variable containing the assigned name of the link. These variables
create the joint.
Use addJoint to define the relationship between the two links. In this case they are attached
together by a revolute joint.
The arguments of the addJoint function are object, parent, child, type, limits, and axis.
After defining bowlPin once, You can create all ten bowling pins from the preceding
ExampleHelperGazeboModel. The following for loop spawns the models in Gazebo using the x and
y vectors.
1-214
Add, Build, and Remove Objects in Gazebo
for i = 1:10
spawnModel(gazebo,pin,[x(i),y(i),0.7]);
pause(1);
end
Remove Models
If the TurtleBot® exists in the scene, remove it. Look in the list of models. Remove the one named
turtlebot3_burger, for this particular world.
if ismember("turtlebot3_burger",getSpawnedModels(gazebo))
removeModel(gazebo,"turtlebot3_burger");
end
Create an ExampleHelperGazeboModel for a Jersey barrier. The object finds this model on the
Gazebo website.
barrier = ExampleHelperGazeboModel("jersey_barrier","gazeboDB");
1-215
1 ROS Featured Examples
Note: You need an Internet connection to spawn models that are not included in these examples.
However, if you have previously spawned a model in your Gazebo simulation, it is cached, so you can
spawn it later without an Internet connection.
spawnedBall = ExampleHelperGazeboSpawnedModel(ball.Name,gazebo)
spawnedBall =
ExampleHelperGazeboSpawnedModel with properties:
Name: 'Ball'
Links: {'link0'}
Joints: {0×1 cell}
Define parameters for the application of force. Here the duration is set to 1 second and the force
vector is set to -75 Newtons in the x direction.
duration = 1; % Seconds
forceVec = [-75 0 0]; % Newtons
1-216
Add, Build, and Remove Objects in Gazebo
applyForce(spawnedBall,sphereLink,duration,forceVec);
pause(5);
1-217
1 ROS Featured Examples
exampleHelperGazeboCleanupBowling;
Clear the workspace of publishers, subscribers, and other ROS-related objects when you are finished
with them.
clear
Use rosshutdown once you are done working with the ROS network. Shut down the global node and
disconnect from Gazebo.
rosshutdown
When you are finished, close the Gazebo window on your virtual machine.
1-218
Add, Build, and Remove Objects in Gazebo
See Also
1-219
1 ROS Featured Examples
This example illustrates a collection of ways to apply forces and torques to models in the Gazebo®
simulator. First, application of torques is examined in three distinct ways using doors for illustration.
Second, two TurtleBot® Create models demonstrate the forcing of compound models. Finally, object
properties (bounce, in this case) are examined using basic balls.
Prerequisites: “Get Started with Gazebo and Simulated TurtleBot” on page 1-205, “Add, Build, and
Remove Objects in Gazebo” on page 1-213
Connect to Gazebo
On your Linux® machine, start Gazebo. If you are using the virtual machine from “Get Started with
Gazebo and Simulated TurtleBot” on page 1-205, click Gazebo Empty world on the desktop.
Initialize ROS by replacing ipaddress with the IP address of the virtual machine. Create an instance
of the ExampleHelperGazeboCommunicator class.
rosinit('http://192.168.233.133:11311')
gazebo = ExampleHelperGazeboCommunicator;
This section demonstrates three distinct methods for applying joint torques. In this case, doors are
used.
Create a door model and spawn three instances in the simulator. Specify the spawn position and
orientation (units are meters and radians).
doormodel = ExampleHelperGazeboModel('hinged_door','gazeboDB');
door1 = spawnModel(gazebo,doormodel,[-1.5 2.0 0]);
door2 = spawnModel(gazebo,doormodel,[-1.5 0.5 0],[0 0 pi]);
door3 = spawnModel(gazebo,doormodel,[-1.5 -2.5 0]);
All units in Gazebo are specified using SI convention. With the doors added, the world looks like this
image:
1-220
Apply Forces and Torques in Gazebo
Note: When the Gazebo simulation is left idle, movable items often drift. If you see the doors moving
slowly without a command, this behavior is normal. This happens because there is often more friction
in the real world than there is in the ideal setting of the Gazebo simulator.
Retrieve handles for the links and joints of the first door and display them.
For the first door, apply a torque directly to the hinge joint.
Apply the torque to the first door using jointTorque. Doing so makes it open and stay open during
the simulation. The first two lines define the stop time and effort parameters for the torque
application. The second entry in the joints cell array is hinged_door::hinge. Use this in the
jointTorque call.
stopTime = 5; % Seconds
effort = 3.0; % Newton-meters
jointTorque(door1, joints{2}, stopTime, effort);
1-221
1 ROS Featured Examples
The second method is to apply a torque to the door link instead of the hinge joint. This method is not
as clean because the torque is applied to the center of mass of the link (which is the door in this case)
and is not applied around the axis of rotation. This method still produces a torque that moves the
door.
Use the applyForce function. The second entry in links is 'hinged_door::door'. Use it in the
applyForce call.
1-222
Apply Forces and Torques in Gazebo
You can apply a force (instead of a torque) directly to the center of mass of the door for it to move.
The commands are:
Note: The forces are always applied from the world coordinate frame and not the object frame. When
you apply this force, it continually operates in the negative y direction. It does not result in a constant
torque on the door.
For the third door, manually define the hinge angle without applying a force or torque.
Use a while loop to create a swinging behavior for the door. Use the setConfig function of the
ExampleHelperGazeboSpawnedModel class.
angle = angle+angdelta;
setConfig(door3,joints{2},angle);
pause(dt);
end
1-223
1 ROS Featured Examples
This section demonstrates creation and external manipulation of a TurtleBot Create. It illustrates
simple control of a more complex object.
Create another TurtleBot in the world by adding the GazeboModel from the database (GazeboDB).
The robot spawned is a TurtleBot Create, not a Kobuki. Apply an external torque to its right wheel.
botmodel = ExampleHelperGazeboModel('turtlebot','gazeboDB');
bot = spawnModel(gazebo,botmodel,[1,0,0]);
The TurtleBot originally spawns facing along the x-axis with an angle of 0 degrees. Change the
orientation to pi/2 radians (90 degrees) using this command:
setState(bot,'orientation',[0 0 pi/2]);
1-224
Apply Forces and Torques in Gazebo
Using applyForce, make the right wheel of the TurtleBot Create move by applying an external
torque to it from the ExampleHelperGazeboSpawnedModel object.
turnStopTime = 1; % Seconds
turnEffort = 0.2; % Newton-meters
jointTorque(bot, botjoints{2}, turnStopTime, turnEffort)
1-225
1 ROS Featured Examples
You can experiment with application of forces to a TurtleBot base instead of to the wheels.
bot2 = spawnModel(gazebo,botmodel,[2,0,0]);
[botlinks2, botjoints2] = getComponents(bot2)
1-226
Apply Forces and Torques in Gazebo
Apply a force to the base in the y direction. See that the base barely moves. The force is acting
perpendicular to the wheel orientation.
The first entry of botlinks2 is 'turtlebot::create::base'. Use botlinks2{1} in the applyForce call.
applyForce(bot2,botlinks2{1},2,[0 1 0]);
applyForce(bot2,botlinks2{1},2,[1 0 0]);
1-227
1 ROS Featured Examples
This section demonstrates the creation of two balls and exposes the 'bounce' property.
Use the ExampleHelperGazeboModel class to create two balls in the simulation. Specify the
parameters of bouncing by using addLink.
spawnModel(gazebo,ballmodel,[0 1 2]);
spawnModel(gazebo,ballmodel,[0 1 3]);
pause(5);
1-228
Apply Forces and Torques in Gazebo
exampleHelperGazeboCleanupApplyForces;
Clear the workspace of publishers, subscribers, and other ROS-related objects when you finish with
them.
clear
Use rosshutdown once you are done working with the ROS network. Shut down the global node and
disconnect from Gazebo.
rosshutdown
Next Steps
• Refer to the next example: “Test Robot Autonomy in Simulation” on page 1-230
1-229
1 ROS Featured Examples
When using robot simulators, it is important to test autonomous algorithms and dynamically alter the
surroundings in the world while the simulation is running. This example shows how to create basic
robot autonomy with Gazebo and how to interact with it. In this example the robot is the TurtleBot®
platform. For specific examples involving the TurtleBot, see the “Communicate with the TurtleBot” on
page 1-243 example.
In this example, you use a timer to control the autonomous aspects of TurtleBot movement. Timers
allow processes to run in the background in regular execution intervals without blocking the
MATLAB® command line. While you can use loops and other methods to examine basic autonomy, the
scheduled execution and non-blocking nature of timers make them the best choice for achieving
autonomous behavior.
Prerequisites: “Get Started with Gazebo and Simulated TurtleBot” on page 1-205, “Add, Build, and
Remove Objects in Gazebo” on page 1-213, “Apply Forces and Torques in Gazebo” on page 1-220
Connect to Gazebo
On your Linux® machine, start Gazebo. If you are using the virtual machine from “Get Started with
Gazebo and Simulated TurtleBot” on page 1-205, use the Gazebo Empty world.
Initialize ROS by replacing the sample IP address with the IP address of the virtual machine. Create
an instance of the ExampleHelperGazeboCommunicator class.
rosinit("http://192.168.178.133:11311")
gazebo = ExampleHelperGazeboCommunicator;
wall = ExampleHelperGazeboModel("grey_wall","gazeboDB");
spawnModel(gazebo,wall,[-2 4 0]);
Create a ExampleHelperGazeboSpawnedModel object for the mobile base and change its
orientation state. Manually rotate the TurtleBot by 90 degrees (π/2 radians) so that it is directly
facing the wall.
turtleBot = ExampleHelperGazeboSpawnedModel("turtlebot3_burger",gazebo);
setState(turtleBot,"orientation",[0 0 pi/2]);
1-230
Test Robot Autonomy in Simulation
This section describes a simple way to create autonomous behavior on a TurtleBot in Gazebo. Use a
basic obstacle avoidance behavior for the TurtleBot. The behavior is to drive forward and turn when
the robot gets very close to an obstacle detected by the laser scanner.
Create global variables for the publisher and publisher message so they can be accessed by the
control algorithm.
global robot
global velmsg
Create the publisher for velocity and the ROS message to carry the information.
robot = rospublisher("/cmd_vel","DataFormat","struct");
velmsg = rosmessage(robot);
1-231
1 ROS Featured Examples
t = timer("TimerFcn",{@exampleHelperGazeboAvoidanceTimer,timerHandles},"Period",0.1,"ExecutionMo
start(t)
The TurtleBot drives toward the wall. Once it gets very close to the wall, it must turn left to avoid
running into it.
Note: If the TurtleBot crashes into the wall, the laser scan is probably not being published through
Gazebo. Restart your Gazebo session and try again.
Add Objects
You can still make changes to the world while the TurtleBot is moving. Add a new wall to the world. If
you add it soon enough, it can block the TurtleBot so that it avoids hitting the wall.
1-232
Test Robot Autonomy in Simulation
stop(t)
delete(t)
Find all objects in the world and remove the ones added manually.
list = getSpawnedModels(gazebo)
1-233
1 ROS Featured Examples
removeModel(gazebo,"grey_wall");
removeModel(gazebo,"grey_wall_0");
Clear the workspace of publishers, subscribers, and other ROS-related objects when you are finished
with them.
clear
Use rosshutdown once you are done working with the ROS network. Shut down the global node and
disconnect from Gazebo.
rosshutdown
1-234
Set Up and Connect to CARLA Simulator
This example shows how to set up and connect to the CARLA simulator using ROS Toolbox to
simulate autonomous driving applications.
You can utilise CARLA Simulator to replicate various driving scenarios spanning from urban to
highway environments and evaluate the effectiveness of their autonomous driving algorithms in a
controlled virtual environment. The simulator includes a variety of sensor models, vehicle dynamics,
and traffic situations, allowing users to simulate real-world settings. You can use Simulink® software
to send steering, braking, and throttle control signals to vehicle controls publisher and control the
CARLA Ego vehicle and investigate various elements of autonomous driving.
Install the latest CARLA simulator on your Linux® host machine. If you are working on a Windows®
machine, download and install the ROS Virtual Machine also. This virtual machine is based on the
Ubuntu® Linux® operating system and is pre-configured to support applications built using ROS
Toolbox.
To start CARLA server on your Windows® host machine, navigate to the installed location of CARLA
and click the application executable CarlaUE4.exe.
1-235
1 ROS Featured Examples
~/carla-ros-bridge/catkin_ws/devel/setup.bash
1 In the same terminal, run the follow command to launch the Ego vehicle in your preferred the
environment of CARLA simulator. For example, you can run the follow command in Town03
environment of CARLA simulator to launch the vehicle near to the gas station.
2 Run this command to change the host address to the host address of your machine.
1-236
Set Up and Connect to CARLA Simulator
rosinit('http://172.18.226.233:11311')
Verify that you can access ROS topics related to the CARLA simulator by running the following
introspection command.
rostopic list
1-237
1 ROS Featured Examples
This example shows how to set up and connect to Unity® Game Engine using ROS Toolbox. You can
use Unity® Game Engine to simulate various robotic applications such as pick-and-place workflow
using a robotic manipulator. Unity® Game Engine supports display and customization of ROS
message visualisations. As of R2023b, ROS Toolbox supports the Noetic Ninjemys distribution for
ROS.
3. Install Unity Editor from Unity Hub. This page uses images of Unity Editor version 2021.3.6f1 LTS.
4. In Unity Hub, select Create project. Unity Editor opens with a new project.
1-238
Set Up and Connect to Unity Game Engine
• URDF Importer— Download this package as a ZIP file from the URDF Importer GitHub repository
to import the robot model from URDF files.
• ROS TCP Connector— Download this package as a ZIP file from the ROS TCP Connector GitHub
repository to connect Unity with the ROS server.
1-239
1 ROS Featured Examples
Start the ROS master from MATLAB. Alternatively, you can connect Unity and MATLAB to a ROS
master running elsewhere.
rosshutdown
rosinit
A ROS TCP endpoint node can facilitate the communication between Unity and ROS for sending and
receiving messages.
Start the ROS TCP endpoint node in MATLAB. You can use a Windows®, or Linux®, or Mac machine.
helperConnectROSToUnity;
1-240
Set Up and Connect to Unity Game Engine
Open the tool to specify the IP address of the machine running the ROS master in the MATLAB
session by selecting Robotics > ROS Settings, from the Unity menu bar. For a detailed guide on
setting up the ROS Connection, see The Unity Side.
Click the play button in Unity to simulate the scene. The console displays any critical errors in your
setup. Address the errors before proceeding with the example. The image here is an example of
simulation of a robotic manipulator for a robotic application.
Ensure the Unity scene is running and that the connection to MATLAB is functioning. When the Unity
sceneries are playing, you will see an overlay on the Game pane. The blue and green arrows next to
ROS IP indicate that there is a connection between Unity and the ROS master.
1-241
1 ROS Featured Examples
answer = questdlg("Click the Play button in Unity. Select Yes once the connection is established.
"Run Unity Scene","Yes","Yes");
switch answer
case "Yes"
% Continue
end
To check the connection status in MATLAB is functioning, verify if MATLAB is receiving the Unity
published ROS topic.
rostopic list
1-242
Communicate with the TurtleBot
This example introduces the TurtleBot® platform and the ways in which MATLAB® users can
interact with it. Specifically, the code in this example demonstrates how to publish messages to the
TurtleBot (such as velocities) and how to subscribe to topics that the TurtleBot publishes (such as
odometry).
Prerequisites: “Get Started with Gazebo and Simulated TurtleBot” on page 1-205 or “Get Started with
a Real TurtleBot” on page 1-119
The TurtleBot must be running. If you are using a real TurtleBot and followed the hardware setup
steps in “Get Started with a Real TurtleBot” on page 1-119, the robot is running. If you are using a
TurtleBot in simulation and followed the setup steps in “Get Started with Gazebo and Simulated
TurtleBot” on page 1-205, launch one of the Gazebo® worlds from the desktop (Gazebo Office, for
instance).
In your MATLAB instance on the host computer, run the following command. Replace ipaddress
with the IP address of the TurtleBot. This line initializes ROS and connects to the TurtleBot.
ipaddress = "http://192.168.178.133:11311";
rosinit(ipaddress)
If the network you are using to connect to the TurtleBot is not your default network adapter, you can
manually specify the IP address of the adapter that is used to connect to the robot. This might happen
if you use a Wireless network, but also have an active Ethernet connection. Replace
IP_OF_TURTLEBOT with the IP address of the TurtleBot and IP_OF_HOST_COMPUTER with the IP
address of the host adapter that is used to connect to the robot:
rosinit("IP_OF_TURTLEBOT","NodeHost","IP_OF_HOST_COMPUTER");
rostopic list
If you do not see any topics, then the network has not been set up properly. Refer to the beginning of
this document for network setup steps.
You can control the movement of the TurtleBot by publishing a message to the /cmd_vel topic. The
message has to be of type geometry_msgs/Twist, which contains data specifying desired linear and
angular velocities. The TurtleBot's movements can be controlled through two different values: the
linear velocity along the X-axis controls forward and backward motion and the angular velocity
around the Z-axis controls the rotation speed of the robot base.
1-243
1 ROS Featured Examples
Create a publisher for the /cmd_vel topic and the corresponding message containing the velocity
values. Use the publisher with structure format messages for better performance.
robotCmd = rospublisher("/cmd_vel","DataFormat","struct") ;
velMsg = rosmessage(robotCmd);
Set the forward velocity (along the X-axis) of the robot based on the velocity variable and publish
the command to the robot. Let it move for a moment, and then bring it to a stop.
velMsg.Linear.X = velocity;
send(robotCmd,velMsg)
pause(4)
velMsg.Linear.X = 0;
send(robotCmd,velMsg)
To view the type of the message published by the velocity topic, execute the following:
geometry_msgs/Twist
The topic expects messages of type geometry_msgs/Twist, which is exactly the type of the velMsg
created above.
To view which nodes are publishing and subscribing to a given topic, use the command: rostopic
info TOPICNAME. The following command lists the publishers and subscribers for the velocity topic.
MATLAB is listed as one of the publishers.
Type: geometry_msgs/Twist
Publishers:
* /matlab_global_node_88195 (http://192.168.178.1:59934/)
Subscribers:
* /gazebo (http://192.168.178.133:39227/)
1-244
Communicate with the TurtleBot
The TurtleBot uses the /odom topic to publish its current position and orientation (collectively
denoted as pose). Since the TurtleBot is not equipped with a GPS system, the pose will be relative to
the pose that the robot had when it was first turned on.
odomSub = rossubscriber("/odom","DataFormat","struct");
Wait for the subscriber to return data, then extract the data and assign it to variables x, y, and z:
odomMsg = receive(odomSub,3);
pose = odomMsg.Pose.Pose;
x = pose.Position.X;
y = pose.Position.Y;
z = pose.Position.Z;
Note: If you see an error, then it is likely that the receive command timed out. Make sure that
odometry is being published and that your network is set up properly.
[x y z]
ans = 1×3
The orientation of the TurtleBot is stored as a quaternion in the Orientation property of pose. Use
quat2eul (Robotics System Toolbox) to convert into the more convenient representation of Euler
angles. To display the current orientation, theta, of the robot in degrees, execute the following lines.
quat = pose.Orientation;
angles = quat2eul([quat.W quat.X quat.Y quat.Z]);
theta = rad2deg(angles(1))
theta = 0.1556
lidarSub = rossubscriber("/scan","DataFormat","struct");
After subscribing to the lidar topic, wait for the data and then display it with rosPlot.
scanMsg = receive(lidarSub);
figure
rosPlot(scanMsg)
1-245
1 ROS Featured Examples
To continuously display updating lidar scans while the robot turns for a short duration, use the
following while loop:
velMsg.Angular.Z = velocity;
send(robotCmd,velMsg)
tic
while toc < 20
scanMsg = receive(lidarSub);
rosPlot(scanMsg)
end
1-246
Communicate with the TurtleBot
velMsg.Angular.Z = 0;
send(robotCmd,velMsg)
Clear the workspace of publishers, subscribers, and other ROS-related objects when you are finished
with them.
clear
Use rosshutdown once you are done working with the ROS network. Shut down the global node and
disconnect from the TurtleBot.
rosshutdown
Next Steps
Refer to the next example: “Explore Basic Behavior of the TurtleBot” on page 1-248
1-247
1 ROS Featured Examples
This example helps you to explore basic autonomy with the TurtleBot®. The described behavior
drives the robot forward and changes its direction when there is an obstacle. You will subscribe to the
laser scan topic and publish the velocity topic to control the TurtleBot.
Make sure you have a TurtleBot running either in simulation through Gazebo® or on real hardware.
Refer to “Get Started with Gazebo and Simulated TurtleBot” on page 1-205 or “Get Started with a
Real TurtleBot” on page 1-119 for the startup procedure. This example uses the Gazebo-simulated
Turtlebot.
In the downloaded virtual machine, click the Gazebo House shortcut to start up the world.
Initialize ROS. Connect to the TurtleBot by replacing ipaddress with the IP address of the
TurtleBot.
ipaddress = "http://192.168.178.133:11311";
rosinit(ipaddress)
Create a publisher for the robot's velocity and create a message for that topic. Communicate using
structure format messages for improved performance.
robot = rospublisher("/cmd_vel","DataFormat","struct");
velmsg = rosmessage(robot);
Make sure that you start the lidar and camera if you are working with real TurtleBot hardware. The
command to start the lidar and camera is:
You must execute the command in a terminal on the TurtleBot. The TurtleBot uses the LDS-01 Lidar
to construct a laser scan that is published on the /scan topic. For the remainder of this example, the
term laser scan refers to data published on this topic.
laser = rossubscriber("/scan","DataFormat","struct");
Wait for one laser scan message to arrive and then display it.
scan = receive(laser,3)
1-248
Explore Basic Behavior of the TurtleBot
AngleMax: 6.2832
AngleIncrement: 0.0175
TimeIncrement: 0
ScanTime: 0
RangeMin: 0.1200
RangeMax: 3.5000
Ranges: [360×1 single]
Intensities: [360×1 single]
figure
rosPlot(scan);
If you see an error, it is possible that the laser scan topic is not receiving any data. If you are running
in simulation, try restarting Gazebo. If you are using hardware, make sure that you started the lidar
and camera properly.
Run the following lines of code, which plot a live laser scan feed for ten seconds. Move an object in
front of the TurtleBot and bring it close enough until it no longer shows up in the plot window. The
laser scan has a limited range because of hardware limitations. The LDS-01 lidar has a minimum
sensing range of 0.12 meters and a maximum range of 3.5 meters. Any objects outside these limits
will not be detected by the sensor.
tic;
while toc < 10
scan = receive(laser,3);
1-249
1 ROS Featured Examples
rosPlot(scan);
end
Based on the distance readings from the laser scan, you can implement a simple obstacle avoidance
algorithm. You can use a simple while loop to implement this behavior.
Set some parameters that will be used in the processing loop. You can modify these values for
different behavior.
Run a loop to move the robot forward and compute the closest obstacles to the robot. When an
obstacle is within the limits of the distanceThreshold, the robot turns. This loop stops after 20
seconds of run time. CTRL+C (or Control+C on the Mac) also stops this loop.
tic;
while toc < 20
% Collect information from laser scan
scan = receive(laser);
rosPlot(scan);
data = rosReadCartesian(scan);
x = data(:,1);
1-250
Explore Basic Behavior of the TurtleBot
y = data(:,2);
% Compute distance of the closest obstacle
dist = sqrt(x.^2 + y.^2);
minDist = min(dist);
% Command robot action
if minDist < distanceThreshold
% If close to obstacle, back up slightly and spin
velmsg.Angular.Z = spinVelocity;
velmsg.Linear.X = backwardVelocity;
else
% Continue on forward path
velmsg.Linear.X = forwardVelocity;
velmsg.Angular.Z = 0;
end
send(robot,velmsg);
end
Clear the workspace of publishers, subscribers, and other ROS related objects when you are finished
with them.
clear
Use rosshutdown once you are done working with the ROS network. Shut down the global node and
disconnect from the TurtleBot.
rosshutdown
1-251
1 ROS Featured Examples
More Information
The laser scan has a minimum range at which it no longer sees objects in its way. That minimum is
somewhere around 0.12 meters from the lidar.
The laser scan cannot detect glass walls. Following is an image from the camera:
1-252
Explore Basic Behavior of the TurtleBot
The trash can is visible, but you cannot see the glass wall. When you use the TurtleBot in areas with
windows or walls that the TurtleBot might not be able to detect, be aware of the limitations of the
laser scan.
Next Steps
Refer to the next example: “Control the TurtleBot with Teleoperation” on page 1-254
1-253
1 ROS Featured Examples
This example shows keyboard control of the TurtleBot® through the use of the
ExampleHelperTurtleBotCommunicator class. The instructions describe how to set up the object
and how to start the keyboard control. Instructions on how to use keyboard control are displayed
when the function is launched. To change parameters of the function, edit the
exampleHelperTurtleBotKeyboardControl function or the
ExampleHelperTurtleBotKeyInput class. For an introduction to using the TurtleBot with
MATLAB®, see the getting started examples (“Get Started with a Real TurtleBot” on page 1-119 or
“Get Started with Gazebo and Simulated TurtleBot” on page 1-205)
Prerequisites: “Communicate with the TurtleBot” on page 1-243, “Explore Basic Behavior of the
TurtleBot” on page 1-248
This example gives an overview of working with a TurtleBot using its native ROS interface. The ROS
Toolbox™ Support Package for TurtleBot based Robots provides a more streamlined interface to
TurtleBot2 hardware.
To install the support package, open Add-Ons > Get Hardware Support Packages on the MATLAB
Home tab and select ROS Toolbox Support Package for TurtleBot based Robots. Alternatively,
use the rosAddons command.
Make sure you have a TurtleBot running either in simulation through Gazebo® or on real hardware.
Refer to “Get Started with Gazebo and Simulated TurtleBot” on page 1-205 or “Get Started with a
Real TurtleBot” on page 1-119 for the startup procedure. If you are using simulation, Gazebo
Office is good for exploring.
Initialize ROS. Connect to the TurtleBot by replacing ipaddress with the IP address of the
TurtleBot.
ipaddress = "http://192.168.178.133:11311";
rosinit(ipaddress)
If you are working with real TurtleBot2 hardware, make sure that you start the Kinect® camera. Run
the following in a terminal on the TurtleBot:
There may be some functionality, sensor, and topic name differences between TurtleBot versions. Be
sure to check which version is being used and the expected topics when controlling it.
Subscribe to the odometry and laser scan topics and make sure that you can receive messages on
these topics. Communicate using structure message format for better performance.
handles.odomSub = rossubscriber("/odom","BufferSize",25,"DataFormat","struct");
receive(handles.odomSub,3);
1-254
Control the TurtleBot with Teleoperation
handles.laserSub = rossubscriber("/scan","BufferSize",5,"DataFormat","struct");
receive(handles.laserSub,3);
if turtleBotVersion == 3
velTopic = "/cmd_vel";
else
velTopic = "/mobile_base/commands/velocity";
end
handles.velPub = rospublisher(velTopic,"DataFormat","struct");
exampleHelperTurtleBotKeyboardControl(handles);
Following are samples of the Command Window, the world plot, and the Gazebo world after some
keyboard teleoperation by the user:
1-255
1 ROS Featured Examples
If you move the TurtleBot too quickly, the obstacle plotting can become messy because of relative
inaccuracies in the odometry topic at high speeds. Here is an example of a messy world plot:
1-256
Control the TurtleBot with Teleoperation
1-257
1 ROS Featured Examples
Once you have exited the function by pressing q, clear the publishers and subscribers on the host.
clear
Use rosshutdown once you are done working with the ROS network. Shut down the global node and
disconnect from the TurtleBot.
rosshutdown
Next Steps
• Refer to the next example: “Obstacle Avoidance with TurtleBot and VFH” on page 1-259
1-258
Obstacle Avoidance with TurtleBot and VFH
This example shows how to use a TurtleBot® with Vector Field Histograms (VFH) to perform obstacle
avoidance when driving a robot in an environment. The robot wanders by driving forward until
obstacles get in the way. The controllerVFH (Navigation Toolbox) object computes steering
directions to avoid objects while trying to drive forward.
Optional: If you do not already have a TurtleBot (simulated or real) set up, install a virtual machine
with the Gazebo simulator and TurtleBot package. See “Get Started with Gazebo and Simulated
TurtleBot” on page 1-205 to install and set up a TurtleBot in Gazebo.
Create a publisher and subscriber to share information with the VFH class. The subscriber receives
the laser scan data from the robot. The publisher sends velocity commands to the robot.
The topics used are for the simulated TurtleBot. Adjust the topic names for your specific robot.
Communicate using structure format messages for better performance.
laserSub = rossubscriber("/scan","DataFormat","struct");
[velPub, velMsg] = rospublisher("/cmd_vel","DataFormat","struct");
Set up VFH object for obstacle avoidance. Set the UseLidarScan property to true. Specify
algorithm properties for robot specifications. Set target direction to 0 in order to drive straight.
vfh = controllerVFH;
vfh.UseLidarScan = true;
vfh.DistanceLimits = [0.05 1];
vfh.RobotRadius = 0.1;
vfh.MinTurningRadius = 0.2;
vfh.SafetyDistance = 0.1;
targetDir = 0;
Set up a Rate object using rateControl (Navigation Toolbox), which can track the timing of your
loop. This object can be used to control the rate the loop operates as well.
rate = rateControl(10);
Create a loop that collects data, calculates steering direction, and drives the robot. Set a loop time of
30 seconds.
Use the ROS subscriber to collect laser scan data. Create a lidarScan object by specifying the
ranges and angles. Calculate the steering direction with the VFH object based on the input laser scan
data. Convert the steering direction to a desired linear and an angular velocity. If a steering direction
is not found, the robot stops and searches by rotating in place.
Drive the robot by sending a message containing the angular velocity and the desired linear velocity
using the ROS publisher.
while rate.TotalElapsedTime < 30
1-259
1 ROS Featured Examples
% Calculate velocities
if ~isnan(steerDir) % If steering direction is valid
desiredV = 0.2;
w = exampleHelperComputeAngularVelocity(steerDir,1);
else % Stop and search for valid direction
desiredV = 0.0;
w = 0.5;
end
This code shows how you can use the Navigation Toolbox™ algorithms to control robots and react to
dynamic changes in their environment. Currently the loop ends after 30 seconds, but other conditions
can be set to exit the loop based on information on the ROS network (i.e. robot position or number of
laser scan messages).
rosshutdown
1-260
Track and Follow an Object
In this example, you explore autonomous behavior that incorporates the Kinect® camera. This
algorithm involves the TurtleBot® looking for a blue ball and then staying at a fixed distance from the
ball. You incorporate safety features, such as bump and cliff sensing.
Prerequisites: “Communicate with the TurtleBot” on page 1-243, “Explore Basic Behavior of the
TurtleBot” on page 1-248, “Control the TurtleBot with Teleoperation” on page 1-254, “Obstacle
Avoidance with TurtleBot and VFH” on page 1-259
This example gives an overview of working with a TurtleBot using its native ROS interface. The ROS
Toolbox™ Support Package for TurtleBot based Robots provides a more streamlined interface to
TurtleBot. It allows you to:
Acquire sensor data and send control commands without explicitly calling ROS commands
To install the support package, open Add-Ons > Get Hardware Support Packages on the
MATLAB® Home tab and select ROS Toolbox™ Support Package for TurtleBot based Robots.
Alternatively, use the roboticsAddons (Robotics System Toolbox) command.
Make sure you have a TurtleBot running either in simulation through Gazebo® or on real hardware.
Refer to “Get Started with Gazebo and Simulated TurtleBot” on page 1-205 or “Get Started with a
Real TurtleBot” on page 1-119 for the startup procedure. If you are using hardware, find a blue ball
to use for tracking. If you are using Gazebo®, the blue ball must be in the world in front of the robot
(make sure that you are using Gazebo Office world).
Initialize ROS. Connect to the TurtleBot by replacing ipaddress with the IP address of the TurtleBot
ipaddress = "192.168.178.133";
rosinit(ipaddress,11311)
Make sure that you have started the Kinect camera if you are working with real TurtleBot hardware.
The command to start the camera is:
Create subscribers for the color camera, the cliff sensor, and the bumper sensor. Create publishers
for emitting sound and for controlling the robot velocity messages. Communicate using messages in
structure format for better performance.
handles.colorImgSub = exampleHelperTurtleBotEnableColorCamera;
1-261
1 ROS Featured Examples
useHardware = exampleHelperTurtleBotIsPhysicalRobot;
if useHardware
handles.cliffSub = rossubscriber("/mobile_base/events/cliff",...
"BufferSize",5,"DataFormat","struct");
handles.bumpSub = rossubscriber("/mobile_base/sensors/bumper_pointcloud",...
"BufferSize",5,"DataFormat","struct");
handles.soundPub = rospublisher("/mobile_base/commands/sound", "kobuki_msgs/Sound",...
"DataFormat","struct");
handles.velPub = rospublisher("/mobile_base/commands/velocity",...
"DataFormat","struct");
else
% Cliff sensor, bumper sensor and sound emitter are only present in
% real TurtleBot hardware
handles.cliffSub = [];
handles.bumpSub = [];
handles.soundPub = [];
handles.velPub = rospublisher("/cmd_vel","DataFormat","struct");
end
Set the parameters for image filtering. Add them to a data structure that will be used in the
algorithm.
Try to visualize the ball to make sure that the ball-finding parameters can locate it. Run the
exampleHelperTurtleBotFindBlueBall function to see if a circle is found. If so, c and m are
assigned values. ball is a binary image created by applying blueness and darkness filters on the
image. View ball to see if the blue ball was properly isolated:
latestImg = rosReadImage(handles.colorImgSub.LatestMessage);
[c,~,ball] = exampleHelperTurtleBotFindBlueBall(latestImg,blueBallParams,useHardware);
Use this example helper to display the real and binary image in a figure and plot a red plus at the
center of the ball.
exampleHelperTurtleBotPlotObject(latestImg,ball,c);
1-262
Track and Follow an Object
In Gazebo, the parameters used might not find the ball, because the threshold values are too
generous. The Gazebo image (left figures) includes parts of the wall and other objects in the white
space. The real image (right figures) looks very saturated with white. Try changing the parameters so
that they are more restrictive:
exampleHelperTurtleBotPlotObject(latestImg,ball,c);
1-263
1 ROS Featured Examples
Now the parameters are too restrictive. Part of the ball does not even show up in the Gazebo image,
and you see nothing in the real image. If you tune the parameters further you can find a middle
ground. In Gazebo, the following parameters should work well. With hardware, ambient lighting
might require you to spend more time fine tuning the parameters.
exampleHelperTurtleBotPlotObject(latestImg,ball,c);
1-264
Track and Follow an Object
Tuning the color thresholds is challenging when compared to tuning them in a simulated environment
like Gazebo.
After you have fine-tuned the parameters, add them to the handles object, which will be used by the
ball tracking algorithm.
handles.params = blueBallParams;
Set controller gains for the TurtleBot. The TurtleBot uses a PID controller to stay at a constant
distance from the ball.
The first set of controller gains is good for a TurtleBot in Gazebo. The second set is good for a
TurtleBot in real hardware. Adjust the gains as you see fit.
1-265
1 ROS Featured Examples
gains.lin = struct("pgain",1/100,"dgain",1/100,"igain",0,"maxwindup",0,"setpoint",0.65);
gains.ang = struct("pgain",1/400,"dgain",1/500,"igain",0,"maxwindup",0,"setpoint",0.5);
gains.lin = struct("pgain",1/100,"dgain",1/1000,"igain",0,"maxwindup",0,"setpoint",0.75);
gains.ang = struct("pgain",1/100,"dgain",1/3000,"igain",0,"maxwindup",0,"setpoint",0.5);
handles.gains = gains;
Define a timer to execute the ball tracking behavior through the callback. Define the stop function to
shut down ROS. Include the handles in the callback function for the timer:
timer2 = timer("TimerFcn",{@exampleHelperTurtleBotTrackingTimer,handles,useHardware},"Period",0.1
timer2.StopFcn = {@exampleHelperTurtleBotStopCallback};
Start the timer using the following command. You see the TurtleBot begin to move around the world,
searching for the ball. When it finds it in the Kinect image, the robot will use the controller to stay at
a fixed distance.
start(timer2);
pause(1);
The bump sensor does not activate in simulation, so the TurtleBot might not recover when it hits a
wall.
If you want to move the blue ball around, use the following commands to apply a force:
g = ExampleHelperGazeboCommunicator();
ballhandle = ExampleHelperGazeboSpawnedModel("unit_sphere_1",g)
duration = 2;
forceVector = [0 4 0];
applyForce(ballhandle,"link",duration,forceVector)
If you want to further explore Gazebo control of the simulation refer to “Add, Build, and Remove
Objects in Gazebo” on page 1-213.
To stop the timer and autonomous behavior, use the following command:
stop(timer2);
If the timer is cleared from the workspace before it is stopped, you must delete it another way. To
stop all timers (even timers in the background) execute the following command:
delete(timerfindall)
Clear the workspace of publishers, subscribers, and other ROS related objects when you are finished
with them
clear
1-266
Track and Follow an Object
More Information
NOTE: Code in this section is not for MATLAB command line execution
In this example, the organization of supporting files allows you great flexibility in customizing and re-
purposing the code. You can alter the ball-finding parameters and the controller gains by changing
values in the handles struct. This example incorporates a timer that manages all aspects of the
control algorithm. This timer is the exampleHelperTurtleBotTrackingTimer. This timer has
Name-Value pairs of Period and ExecutionMode that are set to determine how often the timer
callback is called. Additionally, the stop callback is used. You can incorporate additional callback
functions if you want.
The handles passed into the timer include params for ball-finding and gains for the controller.
switch state
case ExampleHelperTurtleBotStates.Seek
% Object-finding state
[center, scale] = findObject(handles.Tbot.ImColor,handles.params);
% Wander if no circle is found, target the circle if it exists
if isempty(center)
[linearV, angularV] = exampleHelperTurtleBotWanderController();
else
[linearV, angularV] = imageControl(center, scale, size(handles.Tbot.ImColor),hand
setSound(handles.Tbot,2);
end
state = ExampleHelperTurtleBotStates.Seek;
case ExampleHelperTurtleBotStates.Bumper
% Bumper contact state
case ExampleHelperTurtleBotStates.Spin
% Spin state
case ExampleHelperTurtleBotStates.Cliff
% Cliff avoidance
end
1-267
1 ROS Featured Examples
You can add or remove cases from the state machine. If you want to change the state names, use the
ExampleHelperTurtleBotStates class.
The ball-finding algorithm is modular and alterable. It uses two image filters (one on darkness and
one on blueness) masked together to isolate the blue ball. You can change the masks to find a red or
green ball instead. If you want to explore other forms of shape-tracking, the basic workflow remains
the same.
The blue channel is isolated (with some scaling factors) and a threshold is applied to produce a binary
image mask.
These commands isolate the inverse of the blue (with different scaling) and emphasize darkness. A
threshold is applied.
Mask the two binary images together to isolate the dark blue ball.
The constants and scaling factors on the image are user-determined to isolate a specific color. You
can experiment with various combinations.
1-268
Track and Follow an Object
You can also find contiguous regions in the filtered image using regionprops, which is part of the
Image Processing Toolbox.
s = regionprops(ball1, {"Centroid","Area","EquivDiameter"});
There are additional steps to find the ball from this region, which you can find in
exampleHelperTurtleBotFindBlueBall.
The modularity and flexibility of the example code allows you to experiment with your own algorithms
and functions.
1-269
1 ROS Featured Examples
In this example, you implement a ROS node that uses 2-D lidar data from a simulated robot to build a
map of the robot's environment using simultaneous localization and mapping (SLAM). The node uses
this map to estimate the position of the robot. You then generate C++ code and deploy the node to a
remote device.
To assist the ROS node performing SLAM, you deploy a separate ROS node that controls the robot,
making it move through its simulated environment by following the wall. This example uses ROS and
MATLAB® for simulation, and MATLAB Coder™ for code generation and deployment.
Start a ROS-based simulator for a differential-drive robot, and configure a MATLAB connection with
the robot simulator.
To follow along with this example, download a virtual machine using the instructions in “Get Started
with Gazebo and Simulated TurtleBot” on page 1-205, and then follow these steps.
The value of the ROS_IP environment variable, 172.21.8.68, will be used to set the advertised add
Initializing global node /matlab_global_node_59949 with NodeURI http://172.21.8.68:52485/ and Mas
To ensure the robot is in the starting position before simulation, reset the Gazebo scene using the /
gazebo/reset_simulation service. Create a rossvcclient object for the /gazebo/
reset_simulation service and use the call object function to call the service and reset the
Gazebo simulation scene.
gazeboResetClient = rossvcclient("/gazebo/reset_simulation",DataFormat="struct");
call(gazeboResetClient);
To map the entire room, create a node dedicated to robot navigation. The
exampleHelperRobotWallFollowingNode node controls the robot to follow the wall around the
perimeter of the room. Configure and deploy the helper ROS node that reads the lidar data from the
robot and sends geometry_msgs/Twist messages on the /cmd_vel topic.
Create a MATLAB Coder configuration object that uses "Robot Operating System (ROS)"
hardware. Before remote deployment, set these configuration parameters for the Linux virtual
1-270
Build a Map Using Lidar SLAM with ROS in MATLAB
machine. Note that, if you are deploying to a different remote machine, you must change these to the
appropriate parameters for your device.
coderConfig = coder.config("exe");
coderConfig.Hardware = coder.hardware("Robot Operating System (ROS)");
coderConfig.Hardware.BuildAction = "Build and Run";
coderConfig.Hardware.RemoteDeviceAddress = '192.168.47.129';
coderConfig.Hardware.RemoteDeviceUsername = 'user';
coderConfig.Hardware.RemoteDevicePassword = 'password';
coderConfig.Hardware.DeployTo = "Remote Device";
codegen exampleHelperRobotWallFollowingNode -config coderConfig
Create publishers and subscribers to relay messages to and from the simulation over the ROS
network. The subscriber to receives the lidar data from the robot. To control the navigation node,
create three publishers to three topics:
lidarSubscriber = rossubscriber("/scan","sensor_msgs/LaserScan",DataFormat="struct"); % S
Create a lidarSLAM (Navigation Toolbox) object. You must use the addScan object function to add
lidar scans to the object to incrementally build the SLAM map and estimate the robot trajectory.
For code generation, you must specify these properties of the lidarSLAM object: map resolution,
maximum lidar range, and maximum number of scans. To avoid errors, set the maximum number of
scans significantly higher than the number of scans you expect to add to the map over the lifetime of
the node.
The lidarSLAM object maintains a poseGraph (Navigation Toolbox), which holds all of the lidar
scans and the relationships between them that define the map. The LoopClosureThreshold
property of the lidarSLAM object determines how closely a scan must match the poseGraph to
trigger a loop closure. Specifying too low a threshold can cause incorrect loop closures, which apply
erroneous transformations to the map. Specifying too high a threshold can prevent the object from
correcting the map over time as the robot revisits areas it has already explored. You can tune the
threshold for the environment the robot is navigating.
slamObj = lidarSLAM(20,8,1000); % Object that performs SLAM (map resolution 20 cells per mete
slamObj.LoopClosureThreshold = 350; % Raise threshold to prevent smearing
Run a control loop to perform SLAM and direct the robot. This loop consists of these actions:
1-271
1 ROS Featured Examples
• Retrieve the latest position of the robot from the lidarSLAM object, and calculate how far the
robot is from its initial position.
• Check if the robot has moved at least 2 meters from its initial position.
• Once the robot has moved more than 2 meters from its initial position, the node checks every
subsequent scan to see if the robot has returned to that position. Once the robot is within 0.5
meters of its initial position, the control loop ends.
At the end of each iteration, send a start message to the robot to ensure the robot is moving as long
as the control loop is active.
rate = rosrate(10);
robotLeftFlag = false; % Track if the robot has left the start area
while true
[lidarMsg,status,~] = receive(lidarSubscriber); % Get the current lidar scan from the robot
[~,poses] = scansAndPoses(slamObj); % Get the robot poses from the SLAM map
currentDistance = sqrt(sum(poses(end,1:2).^2)); % Take the most recent pose (current pos
if ~robotLeftFlag && currentDistance >= 2 % If the robot has left the start area, begin
robotLeftFlag = true;
end
if robotLeftFlag && currentDistance <= 0.5 % If the robot has completed a lap, end the co
send(stopRobotPublisher,rosmessage(stopRobotPublisher))
break % End control loop
end
end
1-272
Build a Map Using Lidar SLAM with ROS in MATLAB
Every time the lidarSLAM object registers a scan, it checks how similar the new scan is to known
scans. If the new scan is similar enough to a known scan, the object adds a loop closure, which is an
edge between two nearby nodes for which you know the relative positions with high certainty, and
transforms the map to more accurately reflect the environment.
Extract the PoseGraph from the lidarSLAM object, and display the loop closures.
poseGraph = slamObj.PoseGraph;
show(poseGraph,IDs="loopclosures");
title(sprintf("Loop Closures: %d",poseGraph.NumLoopClosureEdges))
1-273
1 ROS Featured Examples
Shut Down
Send a message through the closeRobotPublisher publisher to shut down the navigation node.
Then, reset the Gazebo scene.
send(closeRobotPublisher,rosmessage(closeRobotPublisher))
call(gazeboResetClient);
After you verify the code, you can generate a ROS node for the SLAM routine using MATLAB Coder.
You can then deploy this node on the remote virtual machine running Gazebo. Using deployment, you
can run ROS nodes directly on remote machines. Create a MATLAB Coder configuration object that
uses "Robot Operating System (ROS)" hardware. Before remote deployment, set these
configuration parameters for the Linux virtual machine. Note that, if you are deploying to a different
remote machine, you must change these to the appropriate parameters for your device.
Note: By default, the "Build and Load" build action deploys the node to the device, but does not
automatically run it. If you want the node to run immediately after code generation, use the "Build
and Run" build action, instead.
cfg = coder.config("exe");
cfg.Hardware = coder.hardware("Robot Operating System (ROS)");
cfg.Hardware.BuildAction = "Build and Load";
1-274
Build a Map Using Lidar SLAM with ROS in MATLAB
cfg.Hardware.RemoteDeviceAddress = '192.168.47.129';
cfg.Hardware.RemoteDeviceUsername = 'user';
cfg.Hardware.RemoteDevicePassword = 'password';
cfg.Hardware.DeployTo = "Remote Device";
codegen exampleHelperSlamManagerNode -config cfg
To rerun the deployed ROS nodes from MATLAB, create a rosdevice object, specifying the
deviceAddress, username, and password arguments using the values corresponding to your
remote device. The object establishes an SSH connection between the ROS device and MATLAB.
Check the available nodes on the connected remote device. Verify that the deployed ROS nodes,
exampleHelperSlamManagerNode and exampleHelperRobotWallFollowingNode, exist on the
remote device.
gazeboVMDevice = rosdevice('192.168.47.129','user','password');
gazeboVMDevice.AvailableNodes
Run the ROS nodes deployed on the remote device by using the runNode function. The robot follows
the perimeter wall and stops when it has completed one full lap.
runNode(gazeboVMDevice,'exampleHelperRobotWallFollowingNode')
runNode(gazeboVMDevice,'exampleHelperSlamManagerNode')
1-275
1 ROS Featured Examples
Disconnect from the ROS network after the nodes have finished.
rosshutdown
1-276
Build and Deploy Visual SLAM Algorithm with ROS in MATLAB
In this example, you implement a visual simultaneous localization and mapping (SLAM) algorithm to
estimate the camera poses for the TUM RGB-D Benchmark [1] on page 1-281 dataset. You then
generate C++ code for the visual SLAM algorithm and deploy it as a ROS node to a remote device
using MATLAB®.
The remote device to which you want to deploy the code must have the following dependencies
installed:
• OpenCV 4.5.0 — For more information about downloading the OpenCV source and building it on
your remote device, see OpenCV linux installation.
• g2o library — Download the g2o source and build it on your remote device.
• Eigen3 library — Install eigen3 library using the command $ sudo apt install libeigen3-
dev.
For this example, download a virtual machine (VM) using the instructions in “Get Started with
Gazebo and Simulated TurtleBot” on page 1-205, and then follow these steps.
masterIP = '192.168.192.135';
rosinit(masterIP,11311)
This example uses TUM RGB-D Benchmark [1] on page 1-281 dataset. Download the dataset as a ROS
bag file on the remote device.
$ wget https://cvg.cit.tum.de/rgbd/dataset/freiburg3/rgbd_dataset_freiburg3_long_office_household
This example uses the monovslam (Computer Vision Toolbox) object to implement visual SLAM. For
each new frame added using its addFrame object function, the monovslam object extracts and tracks
1-277
1 ROS Featured Examples
features to estimate camera poses, identify key frames and compute the 3-D map points in the world
frame. The monovslam object also searches for loop closures using the bag-of-features algorithm and
optimizes camera poses using pose graph optimization, once a loop closure is detected. For more
information on visual SLAM pipeline, see “Monocular Visual Simultaneous Localization and Mapping”
(Computer Vision Toolbox).
The helperROSVisualSLAM function implements the visual SLAM algorithm using these steps:
type("helperROSVisualSLAM.m")
function helperROSVisualSLAM()
% The helperROSVisualSLAM function implements the visual SLAM pipeline for
% deployment as a ROS node.
% Copyright 2023 The MathWorks, Inc.
while 1
if hasNewKeyFrame(vslam)
msg = rosmessage('std_msgs/Float64MultiArray', 'DataFormat', 'struct');
% Get map points and camera poses
worldPoints = mapPoints(vslam);
[camPoses] = poses(vslam);
1-278
Build and Deploy Visual SLAM Algorithm with ROS in MATLAB
Use MATLAB Coder™ to generate a ROS node for the visual SLAM algorithm defined by the
helperROSVisualSLAM function . You can then deploy this node on the remote virtual machine.
Create a MATLAB Coder configuration object that uses "Robot Operating System (ROS)"
hardware. Before remote deployment, set these configuration parameters for the Linux virtual
machine. Note that, if you are deploying to a different remote machine, you must change these to the
appropriate parameters for your device.
Note: By default, the "Build and Load" build action deploys the node to the device, but does not
automatically run it. If you want the node to run immediately after code generation, use the "Build
and Run" build action, instead.
cfg = coder.config('exe');
cfg.Hardware = coder.hardware('Robot Operating System (ROS)');
cfg.Hardware.BuildAction = 'Build and load';
cfg.Hardware.CatkinWorkspace = '~/catkin_ws';
cfg.Hardware.RemoteDeviceAddress = '192.168.192.135';
cfg.Hardware.RemoteDeviceUsername = 'user';
cfg.Hardware.RemoteDevicePassword = 'password';
cfg.Hardware.DeployTo = 'Remote Device';
codegen helperROSVisualSLAM -args {} -config cfg -std:c++11
Configure Visualization
Use the helperVisualSLAMViewer object to create a viewer that visualizes map points along with
the camera trajectory and the current camera pose.
viewer = helperVisualSLAMViewer(zeros(0,3),rigidtform3d(eye(4)));
1-279
1 ROS Featured Examples
Create a ROS subscriber to visualize map points and camera poses published by the deployed visual
SLAM node. Assign helperVisualizePointsAndPoses function as a callback to be triggered
whenever the subscriber receives a message from the deployed node.
visualizeSub = rossubscriber('/visualizePoints', 'std_msgs/Float64MultiArray', @(varargin)helperV
On the Ubuntu desktop of the virtual machine, click the ROS Noetic Terminal icon. Source the
catkin workspace.
$ source ~/catkin_ws/devel/setup.bash
To help the deployed node access library dependencies, append /usr/local/lib path to the
environment variable, LD_LIBRARY_PATH.
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
Navigate to the source directory of the deployed helperrosvisualslam node on the remote device.
You must run the node from this directory because the bag of features file used by the deployed node
is present in this directory.
1-280
Build and Deploy Visual SLAM Algorithm with ROS in MATLAB
$ cd ~/catkin_ws/src/helperrosvisualslam/src/
Start playing the ROS bag file in a separate ROS Noetic Terminal.
Disconnect
Disconnect from ROS Network after the nodes have finished execution.
rosshutdown
References
[1] Sturm, Jürgen, Nikolas Engelhard, Felix Endres, Wolfram Burgard, and Daniel Cremers. "A
benchmark for the evaluation of RGB-D SLAM systems". In Proceedings of IEEE/RSJ International
Conference on Intelligent Robots and Systems, pp. 573-580, 2012
Helper Functions
1-281
2
This example shows how to set up ROS 2 within MATLAB, and get information about ROS 2 network
and ROS 2 messages.
Robot Operating System 2 (ROS 2) is the second version of ROS, which is a communication interface
that enables different parts of a robot system to discover, send, and receive data. MATLAB® support
for ROS 2 is a library of functions that allows you to exchange data with ROS 2 enabled physical
robots or robot simulators such as Gazebo®. ROS 2 is built on Data Distribution Service (DDS) which
is an end-to-end middleware that provides features such as discovery, serialization and
transportation. These features align with the design principles of ROS 2 such as distributed discovery
and control over different "Quality of Service" options for transportation. DDS uses Real Time
Publish-Subscribe (RTPS) protocol which provides communication over unreliable network protocols
such as UDP. For more information, see RTPS.
To learn about ROS, see “Get Started with ROS” on page 1-40.
ROS 2 Terminology
• A ROS 2 network comprises different parts of a robot system (such as a planner or a camera
interface) that communicate over ROS 2 network. The network can be distributed over several
machines.
• A ROS 2 node is an entity that contains a collection of related ROS 2 capabilities (such as
publishers and subscribers). A ROS 2 network can have many ROS 2 nodes.
• Publishers and subscribers are different kinds of ROS 2 entities that process data. They exchange
data using messages.
• A publisher sends messages to a specific topic (such as "odometry"), and subscribers to that topic
receive those messages. There can be multiple publishers and subscribers associated with a single
topic.
• A Domain is the physical segmentation of network. It is identified by a unique integer value known
as Domain ID. By default the Domain ID is 0.
• Every node in ROS 2 network on creation advertises its presence to other nodes in the same
Domain ID only.
• ROS 2 network is built on Data Distribution Service (DDS) which makes it possible to connect
multiple nodes across distributed network. For more information, see “Switching Between ROS
Middleware Implementations” on page 2-172.
• RTPS (Real Time publisher-subscriber) protocol provides ROS 2 network with capabilities to send
messages in unreliable network conditions.
• ROS 2 offers variety of Quality of Service (QoS) policies that allow you to tune your
communication between nodes. For more information, see “Manage Quality of Service Policies in
ROS 2” on page 2-23.
For more information, see Robot Operating System2 (ROS 2) and the Concepts section on the ROS 2
website.
Unlike ROS, ROS 2 does not require initialization in MATLAB. The ROS 2 network automatically
starts with creation of nodes.
2-2
Get Started with ROS 2
test1 = ros2node("/test1")
test1 =
ros2node with properties:
Name: '/test1'
ID: 0
Use ros2 node list to see all nodes in the ROS 2 network.
/test1
clear test1
exampleHelperROS2CreateSampleNetwork
Use ros2 node list again and observe the new nodes.
/node_1
/node_2
/node_3
This is a visual representation of the ROS 2 network after the creation of the sample nodes. Use it as
a reference to explore the ROS 2 network in the remainder of the example.
2-3
2 ROS 2 Featured Examples
Run the command ros2 topic list to see available topics in the ROS 2 network. This command
returns three active topics: /pose, /parameter_events, and /scan. The topic /
parameter_events is a global topic which is always present in the ROS 2 network. The nodes use
the /paramater_events topic to monitor or change parameters in the network. You created the /
scan and /pose topics as part of the sample network.
ros2 topic list
/parameter_events
/pose
/rosout
/scan
Each topic is associated with a message type. Run the command ros2 topic list -t to see the
message type of each topic.
ros2 topic list -t
Topic MessageType
_____________________ _________________________________
2-4
Get Started with ROS 2
{'/parameter_events'} {'rcl_interfaces/ParameterEvent'}
{'/pose' } {'geometry_msgs/Twist' }
{'/rosout' } {'rcl_interfaces/Log' }
{'/scan' } {'sensor_msgs/LaserScan' }
The Quality of Service (QoS) policy options change the way the publishers and subscribers handle
and exchange messages.
1. Use the History and Depth QoS policies to determine the behavior of communication objects
based on how you want to place messages in the processing queue. Specify History as one of these
options.
• "keeplast" — Drop messages and retain only the most up-to-date information.
• "keepall" — Keep all the messages received in the queue until they are processed.
2. Use the Reliability QoS policy to guarantee delivery of the messages to the subscriber. Specify
Reliability as one of these options.
• "reliable" — Ensure that the publisher continuously sends the message to the subscriber until
the subscriber confirms receipt of the message.
• "besteffort" — Allow the publisher to send the message only once.
3. Use the Durability QoS policy with the Depth input to control the persistence of messages for
late-joining connections. Specify Durability as one of these options.
• "transientlocal" — The publisher sends the persisted messages to the subscriber if the
subscriber joins the network after the publisher initially sends the messages.
• "volatile" — The publisher does not persist messages after sending them. Subscribers do not
request persisted messages from publishers.
Messages
Publishers and subscribers use ROS 2 messages to exchange information. Each ROS 2 message has
an associated message type that defines the datatypes and layout of information in that message. For
more information, see “Work with Basic ROS 2 Messages” on page 2-13.
Use ros2 msg show to view the properties of a message type. The geometry_msgs/Twist
message type has two properties, Linear and Angular. Each property is a message of type
geometry_msgs/Vector3, which in turn has three properties of type double.
# This expresses velocity in free space broken into its linear and angular parts.
Vector3 linear
Vector3 angular
2-5
2 ROS 2 Featured Examples
float64 x
float64 y
float64 z
Use ros2 msg list to see the full list of message types available in MATLAB.
exampleHelperROS2ShutDownSampleNetwork
You can switch between RMW Implementations for using the data distribution service (DDS), when
you work with ROS 2 in MATLAB® and Simulink®. To configure the required RMW Implementation,
follow these steps.
1. Under the Home tab in the Environment section of the MATLAB toolstrip, open Preferences.
2. Configure the Python™ environment in the ROS Toolbox Preferences dialog box and select an
implementation from the ROS Middleware (RMW) Implementation dropdown list. The default
implementation is rmw_fastrtps_cpp.
2-6
Get Started with ROS 2
3. Switch to a custom RMW implementation by clicking Configure and Switch to Custom RMW
Implementation, which launches the ROS Middleware Configuration dialogue box.
4. Install and build the custom RMW Implementation package to validate the creation of a ROS 2
node with the selected custom RMW implementation.
Next Steps
2-7
2 ROS 2 Featured Examples
A ROS 2 network consists of a multiple ROS 2 nodes. Unlike ROS where the ROS master facilitates
the communication by keeping track of all active ROS entities, ROS 2 is based on Data Distribution
Standard (DDS) which is an end-to-end middleware that provides features such as discovery,
serialization, and transportation. These features align with the design principles of ROS 2 such as
distributed discovery and control over different "Quality of Service" options for transportation.
When you work with ROS 2, you typically follow these steps:
• Connect to a ROS 2 network — To connect to a ROS 2 network, you have to create a ROS 2 node
in MATLAB specifying the network domain ID.
• Exchange Data — Once connected, MATLAB exchanges data with other ROS 2 nodes in the same
domain ID through publishers and subscribers.
• Disconnect from the ROS 2 network — This disconnects MATLAB ROS 2 nodes, publishers and
subscribers from ROS 2 Network.
Use ros2node to create a node in the default domain, which uses the ID of 0. Nodes communicate
with other nodes in the same domain, and are unaware of nodes in other domains.
defaultNode = ros2node("/default_node")
defaultNode =
ros2node with properties:
Name: '/default_node'
ID: 0
Use clear to remove the reference to the node, allowing it to be deleted from the ROS 2 network.
clear defaultNode
To create a node in non-default domain, explicitly specify the domain ID as a second input argument
to ros2node. Below newDomainNode is created in the domain specified by ID 25.
newDomainNode = ros2node("/new_domain_node",25)
newDomainNode =
ros2node with properties:
Name: '/new_domain_node'
ID: 25
To view network information on a specific domain, provide the ID as a parameter to the ros2
function. The following command displays all nodes with domain ID 25.
ros2("node","list","DomainID",25)
2-8
Connect to a ROS 2 Network
/new_domain_node
If the domain ID is not provided explicitly to the node or ros2 command, they use the value of the
ROS_DOMAIN_ID environment variable by default. Use getenv to see the current value. If that
environment variable is unset, or not set to a valid value, the default domain ID of 0 will be used.
getenv("ROS_DOMAIN_ID")
ans =
setenv("ROS_DOMAIN_ID","25")
envDomainNode = ros2node("/env_domain_node")
envDomainNode =
ros2node with properties:
Name: '/env_domain_node'
ID: 25
The ros2 function provides information on the network specified by that environment variable. Use
ros2 node list to view nodes with domain ID 25.
/env_domain_node
/new_domain_node
setenv("ROS_DOMAIN_ID","")
To connect to an existing ROS 2 network, create a node in the desired domain. The ROS 2 network
automatically detects any new nodes created in the same domain in a mechanism called discovery.
Upon starting, each node in ROS 2 advertises its presence to other nodes in the same domain. The
other nodes respond to this advertisement by providing their information to the new node. Nodes
with communication objects like publishers and subscribers establish connections with other nodes if
they have corresponding objects with compatible Quality of Service (QoS) settings. For more
information on QoS settings, see “Manage Quality of Service Policies in ROS 2” on page 2-23.
Discovery is an ongoing process, which enables new nodes to join the network as they are created.
Each node is monitoring the ROS 2 network and act similarly to the ROS master in a ROS network.
Nodes also advertise their absence to other nodes when they go offline.
2-9
2 ROS 2 Featured Examples
The new ROS 2 node sends its advertisement to the existing nodes. The existing nodes respond to the
advertisement and then set up for ongoing communication.
A subnet is a logical partition of an IP network into multiple, smaller network segments. ROS 2 nodes
can communicate with other nodes within the same subnet. To detect the nodes present outside the
subnet, create a DEFAULT_FASTRTPS_PROFILE.xml file to configure the specific DDS
implementation MATLAB uses. Add the list of IP address of systems outside of the subnet with which
to communicate inside address elements. Note that for both systems to communicate, they each
must specify the other system's address in their respective DEFAULT_FASTRTPS_PROFILE.xml files.
Set the domainId element to the appropriate value for the network that is used for communication.
Keep this file in the MATLAB Current Working Directory. Systems using ROS 2 outside of MATLAB
should place this file in the same directory from which the ROS 2 application is run. Below is an
example DEFAULT_FASTRTPS_PROFILES.xml file.
<?xml version="1.0" encoding="UTF-8" ?>
<profiles>
<participant profile_name="participant_win" is_default_profile="true">
<rtps>
<builtin>
2-10
Connect to a ROS 2 Network
<metatrafficUnicastLocatorList>
<locator/>
</metatrafficUnicastLocatorList>
<initialPeersList>
<locator>
<udpv4>
<address>192.34.17.36</address>
</udpv4>
</locator>
<locator>
<udpv4>
<address>182.30.45.12</address>
</udpv4>
</locator>
<locator>
<udpv4>
<address>194.158.78.29</address>
</udpv4>
</locator>
</initialPeersList>
</builtin>
</rtps>
</participant>
</profiles>
ROS 2 advertises information to the nodes present in the systems with IP addresses listed inside the
DEFAULT_FASTRTPS_PROFILES.xml. No information from the nodes in the other machine outside
the subnet will be received if DEFAULT_FASTRTPS_PROFILES.xml is either not present or does not
contain the correct IP addresses.
2-11
2 ROS 2 Featured Examples
Next Steps
See Also
Related Examples
• “Get Started with ROS 2 in Simulink” on page 2-65
2-12
Work with Basic ROS 2 Messages
This example examines various ways to create, inspect, and populate ROS 2 messages in MATLAB,
that are commonly encountered in robotics applications.
ROS messages are the primary container for exchanging data in ROS 2. Publishers and subscribers
exchange data using messages on specified topics to carry data between nodes. For more information
on sending and receiving messages, see “Exchange Data with ROS 2 Publishers and Subscribers” on
page 2-19.
To identify its data structure, each message has a message type. For example, sensor data from a
laser scanner is typically sent in a message of type sensor_msgs/LaserScan. Each message type
identifies the data elements that are contained in a message. Every message type name is a
combination of a package name, followed by a forward slash /, and a type name:
MATLAB® supports many ROS 2 message types that are commonly encountered in robotics
applications. This example examines some of the ways to create, inspect, and populate ROS 2
messages in MATLAB.
Prerequisites: “Get Started with ROS 2” on page 2-2, “Connect to a ROS 2 Network” on page 2-8
Use ros2 topic list -t to find the available topics and their associated message type.
ros2 topic list -t
Topic MessageType
_____________________ _________________________________
{'/parameter_events'} {'rcl_interfaces/ParameterEvent'}
{'/pose' } {'geometry_msgs/Twist' }
{'/rosout' } {'rcl_interfaces/Log' }
{'/scan' } {'sensor_msgs/LaserScan' }
To find out more about the topic message type, use ros2message to create an empty message of the
same type. ros2message supports tab completion for the message type. To quickly complete
2-13
2 ROS 2 Featured Examples
message type names, type the first few characters of the name you want to complete, and then press
the Tab key.
scanData = ros2message("sensor_msgs/LaserScan")
The created message, scanData, has many fields associated with data that you typically received
from a laser scanner. For example, the minimum sensing distance is stored in the range_min
property and the maximum sensing distance in range_max property.
clear scanData
To see a complete list of all message types available for topics and services, use ros2 msg list.
ROS 2 messages are represented as structures and the message data is stored in fields. MATLAB
provides convenient ways to find and explore the contents of messages.
Use ros2 msg show to view the definition of the message type.
# This expresses velocity in free space broken into its linear and angular parts.
Vector3 linear
Vector3 angular
If you subscribe to the /pose topic, you can receive and examine the messages that are sent.
controlNode = ros2node("/base_station");
poseSub = ros2subscriber(controlNode,"/pose","geometry_msgs/Twist")
poseSub =
ros2subscriber with properties:
TopicName: '/pose'
LatestMessage: []
MessageType: 'geometry_msgs/Twist'
NewMessageFcn: []
History: 'keeplast'
Depth: 10
Reliability: 'reliable'
2-14
Work with Basic ROS 2 Messages
Durability: 'volatile'
Use receive to acquire data from the subscriber. Once a new message is received, the function
returns it and stores it in the posedata variable. Specify a timeout of 10 seconds for receiving
messages.
poseData = receive(poseSub,10)
The message has a type of geometry_msgs/Twist. There are two other fields in the message:
linear and angular. You can see the values of these message fields by accessing them directly.
poseData.linear
poseData.angular
You can see that each of the values of these message fields is actually a message in itself.
geometry_msgs/Twist is a composite message made up of two geometry_msgs/Vector3
messages.
Data access for these nested messages works exactly the same as accessing the data in other
messages. Access the x component of the linear message using this command:
xPose = poseData.linear.x
xPose = 0.0206
You can also set message property values. Create a message with type geometry_msgs/Twist.
twist = ros2message("geometry_msgs/Twist")
2-15
2 ROS 2 Featured Examples
The numeric properties of this message are initialized to 0 by default. You can modify any of the
properties of this message. Set the linear.y field to 5.
twist.linear.y = 5;
You can view the message data to make sure that your change took effect.
twist.linear
Once a message is populated with your data, you can use it with publishers and subscribers.
Copy Messages
ROS 2 messages are structures. They can be copied directly to make a new message. The copy and
the original messages each have their own data.
Make a new empty message to convey temperature data, then make a copy for modification.
tempMsgBlank = ros2message("sensor_msgs/Temperature");
tempMsgCopy = tempMsgBlank
Modify the temperature property of tempMsg and notice that the contents of tempMsgBlank
remain unchanged.
tempMsgCopy.temperature = 100
tempMsgBlank
It may be useful to keep a blank message structure around, and only set the specific fields when there
is data for it before sending the message.
2-16
Work with Basic ROS 2 Messages
thermometerNode = ros2node("/thermometer");
tempPub = ros2publisher(thermometerNode,"/temperature","sensor_msgs/Temperature");
tempMsgs(10) = tempMsgBlank; % Pre-allocate message structure array
for iMeasure = 1:10
% Copy blank message fields
tempMsgs(iMeasure) = tempMsgBlank;
2-17
2 ROS 2 Featured Examples
You can save messages and store the contents for later use.
poseData = receive(poseSub,10)
Save the pose data to a MAT file using the save function.
save("poseFile.mat","poseData")
Before loading the file back into the workspace, clear the poseData variable.
clear poseData
Now you can load the message data by calling the load function. This loads the poseData from
above into the messageData structure. poseData is a data field of the struct.
messageData = load("poseFile.mat")
messageData.poseData
delete("poseFile.mat")
Remove the sample nodes, publishers, and subscribers from the ROS 2 network.
exampleHelperROS2ShutDownSampleNetwork
Next Steps
2-18
Exchange Data with ROS 2 Publishers and Subscribers
This example shows how to publish and subscribe to topics in a ROS 2 network.
The primary mechanism for ROS 2 nodes to exchange data is to send and receive messages.
Messages are transmitted on a topic and each topic has a unique name in the ROS 2 network. If a
node wants to share information, it must use a publisher to send data to a topic. A node that wants to
receive that information must use a subscriber for that same topic. Besides its unique name, each
topic also has a message type, which determines the type of messages that are allowed to be
transmitted in the specific topic.
• Topics are used for many-to-many communication. Multiple publishers can send messages to the
same topic and multiple subscribers can receive them.
• Publisher and subscribers are decoupled through topics and can be created and destroyed in any
order. A message can be published to a topic even if there are no active subscribers.
Besides how to publish and subscribe to topics in a ROS 2 network, this example also shows how to:
Prerequisites: “Get Started with ROS 2” on page 2-2, “Connect to a ROS 2 Network” on page 2-8
2-19
2 ROS 2 Featured Examples
/parameter_events
/pose
/rosout
/scan
Assume you want to subscribe to the /scan topic. Use ros2subscriber to subscribe to the /scan
topic. Specify the name of the node with the subscriber. If the topic already exists in the ROS 2
network, ros2subscriber detects its message type automatically, so you do not need to specify it.
detectNode = ros2node("/detection");
pause(5)
laserSub = ros2subscriber(detectNode,"/scan");
pause(5)
Use receive to wait for a new message. Specify a timeout of 10 seconds. The output scanData
contains the received message data. status indicates whether a message was received successfully
and statustext provides additional information about the status.
[scanData,status,statustext] = receive(laserSub,10);
You can now remove the subscriber laserSub and the node associated to it.
clear laserSub
clear detectNode
Instead of using receive to get data, you can specify a function to be called when a new message is
received. This allows other MATLAB code to execute while the subscriber is waiting for new
messages. Callbacks are essential if you want to use multiple subscribers.
The global variables pos and orient are assigned in the exampleHelperROS2PoseCallback
function when new message data is received on the /pose topic.
function exampleHelperROS2PoseCallback(message)
% Declare global variables to store position and orientation
global pos
global orient
% Extract position and orientation from the ROS message and assign the
% data to the global variables.
pos = [message.linear.x message.linear.y message.linear.z];
orient = [message.angular.x message.angular.y message.angular.z];
end
Wait a moment for the network to publish another /pose message. Display the updated values.
2-20
Exchange Data with ROS 2 Publishers and Subscribers
pause(3)
disp(pos)
disp(orient)
If you type in pos and orient a few times in the command line you can see that the values are
continuously updated.
clear poseSub
clear controlNode
Note: There are other ways to extract information from callback functions besides using globals. For
example, you can pass a handle object as additional argument to the callback function. See the
“Create Callbacks for Graphics Objects” documentation for more information about defining callback
functions.
Publish Messages
Create a publisher that sends ROS 2 string messages to the /chatter topic.
chatterPub = ros2publisher(node_1,"/chatter","std_msgs/String");
chatterMsg = ros2message(chatterPub);
chatterMsg.data = 'hello world';
Use ros2 topic list to verify that the /chatter topic is available in the ROS 2 network.
/chatter
/parameter_events
/pose
/rosout
/scan
chatterSub = ros2subscriber(node_2,"/chatter",@exampleHelperROS2ChatterCallback)
chatterSub =
ros2subscriber with properties:
TopicName: '/chatter'
LatestMessage: []
MessageType: 'std_msgs/String'
NewMessageFcn: @exampleHelperROS2ChatterCallback
History: 'keeplast'
Depth: 10
Reliability: 'reliable'
2-21
2 ROS 2 Featured Examples
Durability: 'volatile'
Publish a message to the /chatter topic. Observe that the string is displayed by the subscriber
callback.
send(chatterPub,chatterMsg)
pause(3)
ans =
'hello world'
The exampleHelperROS2ChatterCallback function was called when the subscriber received the
string message.
Remove the sample nodes, publishers and subscribers from the ROS 2 network. Also clear the global
variables pos and orient
Next Steps
2-22
Manage Quality of Service Policies in ROS 2
Quality of Service (QoS) policy options allow for changing the behavior of communication within a
ROS 2 network. QoS policies are modified for specific communication objects, such as publishers and
subscribers, and change the way that messages are handled in the object and transported between
them. For any messages to pass between two communication objects, their QoS policies must be
compatible.
The history and depth QoS policies determine the behavior of communication objects when messages
are being made available faster than they can be processed. This is primarily a concern for
subscribers that are receiving messages while still processing the previous message. Messages are
placed into a processing queue, which can affect publishers as well. History has the options of:
• "keeplast" - The message processing queue has a maximum size equal to the Depth value. If
the queue is full, the oldest messages are dropped to make room for newer ones.
• "keepall" - The message processing queue attempts to keep all messages received in the queue
until processed.
Under either history setting, the queue size is subject to hardware resource limits. If the subscriber
calls a callback when new messages are received, the queue size is also limited by the maximum
recursion limit.
In situations where it is important to process all messages, increasing the Depth value or using
History,"keepall" is recommended.
This example shows how to set up a publisher and subscriber for sending and receiving point cloud
messages. The publisher Depth is 20 and the subscriber history is set to "keepall". The subscriber
uses a call back to plot the time stamp for each message to show the timing of processing each
message. The initial messages take longer to process, but all the messages are eventually processed
from the queue.
2-23
2 ROS 2 Featured Examples
localizationSub = ros2subscriber(robotNode,"/laser_scan",...
@(msg)exampleHelperROS2PlotTimestamps(msg,hAxesLidar),...
"History","keepall");
In situations where messages being dropped is less important, and only the most up-to-date
information really matters, a smaller queue is recommended to improve performance and ensure the
most recent information is being used. This example shows quicker processing of the first messages
and still gets all the messages. Depending on your resources however, you may see messages get
dropped.
2-24
Manage Quality of Service Policies in ROS 2
scanDisplaySub = ros2subscriber(robotNode,"/laser_scan",...
@(msg)exampleHelperROS2PlotTimestamps(msg,hAxesLidar2),...
"History","keeplast","Depth",1);
for iMsg = 1:numel(lidarScans)
send(lidarPub,lidarScans(iMsg))
end
Reliability
The reliability QoS policy determines whether to guarantee delivery of messages, and has the
options:
• "reliable" - The publisher continuously sends the message to the subscriber until the
subscriber confirms receipt of the message.
• "besteffort" - The publisher sends the message only once, and does not confirm that the
subscriber receives it.
Reliable
A "reliable" connection is useful when all of the data must be processed, and any dropped
messages may impact the result. This example publishes Odometry messages and uses a subscriber
callback to plot the position. Because for the "reliable" setting, all the positions are plotted in the
figure.
2-25
2 ROS 2 Featured Examples
odomPlotSub = ros2subscriber(robotNode,"/odom",...
@(msg)exampleHelperROS2PlotOdom(msg,hAxesReliable,"ok"),...
"Reliability","reliable");
2-26
Manage Quality of Service Policies in ROS 2
Best Effort
This example uses a "besteffort" subscriber, but still receives all messages due to the low impact
on the network.
hFig = figure;
hAxesBestEffort = axes("Parent",hFig);
title("Message Timeline (Best Effort Connection)")
odomTimingSub = ros2subscriber(robotNode,"/odom",...
@(msg)exampleHelperROS2PlotTimestamps(msg,hAxesBestEffort),...
"Reliability","besteffort");
for iMsg = 1:numel(odomData)
send(odomPub,odomData(iMsg))
end
Compatibility
2-27
2 ROS 2 Featured Examples
publishers do not connect to a "reliable" subscriber because messages are not guaranteed to be
delivered. In the opposite situation, a "reliable" publisher and a "besteffort" subscriber do
connect, but the connection behaves as "besteffort" with no confirmation when receiving
messages. This example shows a "besteffort" publisher sending messages to the "besteffort"
subscriber already set up. Again, due to the low impact on the network, the "besteffort"
connection is sufficient to process all the messages.
% Reactivate reliable subscriber to show no messages received
odomPlotSub.NewMessageFcn = @(msg)exampleHelperROS2PlotOdom(msg,hAxesReliable,"*r");
The durability QoS policy controls the persistence of messages for late-joining connections, and has
the options:
• "transientlocal" - For a publisher, messages that have already been sent are maintained. If a
subscriber joins the network with "transientlocal" durability after that, then the publisher
sends the persisted messages to the subscriber.
• "volatile" - Publishers do not persist messages after sending them, and subscribers do not
request persisted messages from publishers.
x: 0.1047
y: -2.3168
theta: -8.5194
2-28
Manage Quality of Service Policies in ROS 2
posePlotSub = ros2subscriber(robotNode,"/bot_position",...
@(msg)plot(hAxesMoreMsgs,msg.x,msg.y,"ok"),...
"Durability","transientlocal","Depth",20);
pause(3) % Allow messages to arrive and be plotted
Compatibility
Similar to reliability, incompatible durability settings can prevent communication between publishers
and subscribers. A subscriber with "transientlocal" durability requires a publisher with
"transientlocal" durability. If a publisher is "volatile", no connection is established with
"transientlocal" subscribers. If a publisher is "transientlocal" and the subscriber
"volatile", then that connection is created, without sending persisting messages to the subscriber.
% Reset plotting behavior
posePlotSub.NewMessageFcn = @(msg)plot(hAxesMoreMsgs,msg.x,msg.y,"xr");
2-29
2 ROS 2 Featured Examples
send(volatilePosePub,robotPositions(iMsg))
pause(0.2) % Allow for processing time
end
2-30
Manage Quality of Service Policies in ROS 2 Application with TurtleBot
This example demonstrates best practices in managing Quality of Service (QoS) policies for an
application using ROS 2. QoS policies allow for the flexible tuning of communication behavior
between publishers and subscribers, and change the way that messages are transported within a ROS
2 network. For more information, see “Manage Quality of Service Policies in ROS 2” on page 2-23.
In this example, you use a MATLAB® script to launch a teleoperation controller for a simulated
TurtleBot® to follow a path in based on instructions in the environment.
Start a ROS 2 simulator for a TurtleBot® and configure the MATLAB connection with the robot
simulator.
This example uses a virtual machine (VM). Download the VM using the instructions in “Get Started
with Gazebo and Simulated TurtleBot” on page 1-205.
2-31
2 ROS 2 Featured Examples
2-32
Manage Quality of Service Policies in ROS 2 Application with TurtleBot
• Enter these commands in the MATLAB Command Window to verify that the topics from the robot
simulator are visible in MATLAB.
setenv('ROS_DOMAIN_ID','25')
ros2('topic','list')
/camera/camera_info
/camera/image_raw
/clock
/cmd_vel
/imu
/joint_states
/odom
/parameter_events
/rosout
/scan
/tf
domainID = 25;
robotDataProcessingNode = ros2node("/robotDataProcessingNode",domainID);
humanOperatorNode = ros2node("/humanOperatorNode",domainID);
This diagram summarizes the interaction between MATLAB and the robot simulator.
2-33
2 ROS 2 Featured Examples
Create publishers and subscribers to relay messages to and from the robot simulator over the ROS 2
network. A publisher and subscriber pair can have compatible, but different QoS policies unless any
QoS policies of the subscriber are more stringent than those of the publisher. For example, you must
relay the velocity commands in a reliable channel from the publisher to the subscriber. To ensure
compatibility, specify the "Reliability" and "Durability" QoS policies of the publisher as
"reliable" and "transientlocal", respectively. This configuration indicates the maximum quality
that the controller provides for sending messages reliably. If the receiver on the robot is not equipped
with good hardware to reliably process the messages, you can set a lower QoS standard for the
subscriber. Thus, specify the "Reliability" and "Durability" QoS policies of the subscriber to
"besteffort" and "volatile" respectively, which is the minimum quality that the receiver is
willing to accept. These QoS settings demonstrate the best practice for specifying "Reliability",
and "Durability" parameters. Publishers with policies of "besteffort" or "volatile" do not
connect to subscribers with policies of "reliable", or "transientlocal". Because the subscriber
is asking for a higher QoS standard than the publisher is offering, delivery of the publisher messages
is not guaranteed.
velPub = ros2publisher(humanOperatorNode,"/cmd_vel","geometry_msgs/Twist","Reliability","reliable
2-34
Manage Quality of Service Policies in ROS 2 Application with TurtleBot
To receive the latest reading of sensor data being published at a high rate, set the "Reliability"
QoS policy of the subscriber to "besteffort" and, the "Durability" policy to "volatile", with a
small "Depth" value. These settings enable high-speed communication by reducing the overhead
time for sending and receiving message confirmation and ensure that the subscribers process the
most recent messages. These settings can result in subscribers not receiving messages in lossy or
high-traffic networks, or not processing all messages received if the processing cannot keep up. Apply
this QoS policy to both the camera and lidar sensor.
imageSub = ros2subscriber(robotDataProcessingNode,"/camera/image_raw","sensor_msgs/Image","Reliab
laserSub = ros2subscriber(robotDataProcessingNode,"/scan","sensor_msgs/LaserScan","Reliability","
Because odometry is critical in placing the lidar scans in context, dropped odometry messages result
in misleading lidar readings. To prevent dropped messages, the reliability and durability policies for
the odometry publisher in the Gazebo node are "reliable" and "transientlocal", respectively.
As this particular algorithm does not need past messages, specify QoS policies for the odometry
subscriber as "reliable" and "volatile".
odomSub = ros2subscriber(robotDataProcessingNode,"/odom","nav_msgs/Odometry","Reliability","relia
In this example, the information about the current stage of the robot updates at a low frequency, and
the value in the latest message received applies until the subscriber receives the next message.
Create a publisher that sends messages reliably and stores them for late-joining subscribers. If the
"Depth" value of the publisher is large enough, it is possible for subscribers to request the entire
history of the publisher when they join the network. Configure the publisher of the /signCounter
topic with "Reliability" policy set to "reliable", "Durability" policy set to
"transientlocal", and "Depth" value set to 100.
stagePub = ros2publisher(robotDataProcessingNode,"/signCounter","std_msgs/Int8","Reliability","re
This table summarizes the QoS policies for the five pairs of publishers and subscribers.
2-35
2 ROS 2 Featured Examples
For messages to pass successfully from publisher to subscriber over a topic, their QoS policies must
be compatible. The publishers in the table do not always have the same QoS parameters as their
corresponding subscribers, but they are still compatible. For example, in the camera sensor, velocity
command, and laser scan topics, the "reliable" publishers and "besteffort" subscribers are
able to connect. The connection behaves as a "besteffort" connection, with no confirmation when a
subscriber receives a message. Similarly, in the odometry and velocity command topics, the
"transientlocal" publishers and "volatile" subscribers have compatible QoS policies. The
publishers retain the published messages while the subscribers do not request any previously sent
messages.
Run the teleoperation controller to move the robot. Process the sensor data to help the robot
visualize and navigate in the environment. When the robot moves close to a sign, the sign-detecting
algorithm outputs a confirmation message with the instruction to find the next sign. This task repeats
until the robot reaches the stop sign. For information on running the robot in autonomous mode, see
“Sign Following Robot with ROS 2 in MATLAB” on page 2-118.
[laserPlotObj,imageAxesHandle,signText,axesHandle] = ExampleHelperQoSTurtleBotSetupVisualizer(vel
% Wait to receive sensor messages before starting the control loop
receive(laserSub,5);
receive(odomSub,5);
receive(imageSub,5);
% Set callback functions for subscribers
imageSub.NewMessageFcn = @(msg)ExampleHelperQoSTurtleBotPlotImage(msg,imageAxesHandle);
2-36
Manage Quality of Service Policies in ROS 2 Application with TurtleBot
laserSub.NewMessageFcn = @(msg)ExampleHelperQoSTurtleBotPlotScan(msg,laserPlotObj,odomSub);
r = rateControl(10);
LastStage = false;
while ~LastStage
[~,blobSize,blobX] = ExampleHelperQoSTurtleBotProcessImg(imageSub.LatestMessage); % Process i
[nextStage,LastStage,stageMsg,textHandle] = ExampleHelperQoSTurtleBotSignDetection(LastStage,
if nextStage && ~LastStage % When the algorithm detects a sign, publish a message to keep tr
send(stagePub,stageMsg);
end
waitfor(r);
end
2-37
2 ROS 2 Featured Examples
2-38
Manage Quality of Service Policies in ROS 2 Application with TurtleBot
When sensors detect the stop sign, create a new subscriber in the /humanOperatorNode node to
request the past messages in the history of the publisher. Extract information on all the detected
signs.
send(stagePub,stageMsg);
stageSub = ros2subscriber(humanOperatorNode,"/signCounter","std_msgs/Int8","Reliability","reliabl
stageSub.NewMessageFcn = @(msg)ExampleHelperQoSTurtleBotSignCountUpdate(msg,textHandle);
pause(2); % Allow time for the persisting messages to be received and processed
2-39
2 ROS 2 Featured Examples
2-40
Manage Quality of Service Policies in ROS 2 Application with TurtleBot
In low-traffic and lossless networks, there is little difference between reliable and best-effort
communication. To visualize how different QoS policies handle lossy or high-traffic network
connections, use the traffic control utility to simulate a network with delay. On the VM, open a new
terminal and enter this command.
The traffic control utility simulates a fixed amount of delay to all packets on the ens33 network
interface. Run the example again, observing the stuttering effect of the image stream due to some
dropped frames in "best-effort" communication. If you change the image subscriber to
"reliable", the image stream smooths out, but lags behind the actual robot viewpoint slightly due
to the network delay.
To clean up, remove the artificial network lag by entering this command.
2-41
2 ROS 2 Featured Examples
2-42
Call and Provide ROS 2 Services
ROS supports two main communication mechanisms: topics and services. Topics have publishers and
subscribers and are used for sending and receiving messages (see “Exchange Data with ROS 2
Publishers and Subscribers” on page 2-19). Services, on the other hand, implement a tighter coupling
by allowing request-response communication. A service client sends a request message to a service
server and waits for a response. The server will use the data in the request to construct a response
message and sends it back to the client. Each service has a type that determines the structure of the
request and response messages.
• A service request (or service call) is used for one-to-one communication. A single node will initiate
the request and only one node will receive the request and send back a response.
• A service client and a service server are tightly coupled when a service call is executed. The
server needs to exist at the time of the service call and once the request is sent, the client will
block until a response is received.
This example shows you how to set up service servers to advertise a service to the ROS network. In
addition, you will learn how to use service clients to call the server and receive a response.
Prerequisites: “Get Started with ROS 2” on page 2-2, “Connect to a ROS 2 Network” on page 2-8,
“Exchange Data with ROS 2 Publishers and Subscribers” on page 2-19
2-43
2 ROS 2 Featured Examples
Before examining service concepts, create the sample ROS 2 network with three nodes to simulate a
realistic network.
node_1 = ros2node("node_1");
node_2 = ros2node("node_2");
node_3 = ros2node("node_3");
Suppose you want to make a simple service server that displays "A service client is calling" when you
call the service. Create the service using the ros2svcserver command. Specify the service name,
the service message type and the node to attach the server. Also define the callback function as
exampleHelperROSEmptyCallback. Callback functions for service servers have a very specific
signature. For details, see the documentation of ros2svcserver.
testserver = ros2svcserver(node_1,"/service_example","std_srvs/Empty",@exampleHelperROS2EmptyCall
testserver =
ros2svcserver with properties:
ServiceType: 'std_srvs/Empty'
ServiceName: '/service_example'
NewRequestFcn: @exampleHelperROS2EmptyCallback
History: 'keeplast'
Depth: 10
Reliability: 'reliable'
Durability: 'volatile'
You can see your new service, /test, when you list all services in the ROS network.
ros2("service","list");
/_matlab_introspec__0_rmw_fastrtps_cpp/describe_parameters
/_matlab_introspec__0_rmw_fastrtps_cpp/get_parameter_types
/_matlab_introspec__0_rmw_fastrtps_cpp/get_parameters
/_matlab_introspec__0_rmw_fastrtps_cpp/list_parameters
/_matlab_introspec__0_rmw_fastrtps_cpp/set_parameters
/_matlab_introspec__0_rmw_fastrtps_cpp/set_parameters_atomically
/node_1/describe_parameters
/node_1/get_parameter_types
/node_1/get_parameters
/node_1/list_parameters
/node_1/set_parameters
/node_1/set_parameters_atomically
/node_2/describe_parameters
/node_2/get_parameter_types
/node_2/get_parameters
/node_2/list_parameters
/node_2/set_parameters
/node_2/set_parameters_atomically
/node_3/describe_parameters
/node_3/get_parameter_types
/node_3/get_parameters
/node_3/list_parameters
/node_3/set_parameters
/node_3/set_parameters_atomically
/service_example
2-44
Call and Provide ROS 2 Services
Use service clients to request information from a ROS 2 service server. To create a client, use
ros2svcclient with the service name as the argument.
Create a service client for the /test service that we just created and attach it to a different node.
testclient = ros2svcclient(node_2,"/service_example","std_srvs/Empty")
testclient =
ros2svcclient with properties:
ServiceType: 'std_srvs/Empty'
ServiceName: '/service_example'
History: 'keeplast'
Depth: 10
Reliability: 'reliable'
Durability: 'volatile'
Create an empty request message for the service. Use the ros2message function and pass the client
as the first argument. This will create a service request function that has the message type that is
specified by the service.
testreq = ros2message(testclient)
Ensure that the service is connected to the client, waiting for them to connect if necessary.
waitForServer(testclient,"Timeout",3)
When you want to get a response from the server, use the call function, which calls the service
server and returns a response. The service server you created before will return an empty response.
In addition, it will call the exampleHelperROSEmptyCallback function and displays the string "A
service client is calling". You can also define a Timeout parameter, which indicates how long the
client should wait for a response. status and statustext outputs provide additional information
about the status of the response.
testresp = call(testclient,testreq,"Timeout",3)
If the call function above fails, it will error. Instead of an error, if you would prefer to react to a call
failure using conditionals, return the status and statustext outputs from the call function. The status
output indicates if the call succeeded, while statustext provides additional information. Similar
outputs can be returned from waitForServer.
numCallFailures = 0;
[testresp,status,statustext] = call(testclient,testreq,"Timeout",3);
if ~status
numCallFailures = numCallFailues + 1;
fprintf("Call failure number %d. Error cause: %s\n",numCallFailures,statustext)
else
2-45
2 ROS 2 Featured Examples
disp(testresp)
end
MessageType: 'std_srvs/EmptyResponse'
Up to now, the service server has not done any meaningful work, but you can use services for
computations and data manipulation. Create a service that adds two integers.
There is an existing service type, example_interfaces/AddTwoInts, that we can use for this task.
You can inspect the structure of the request and response messages by calling ros2 msg show. The
request contains two integers, a and b, and the response contains their addition in sum.
ros2 msg show example_interfaces/AddTwoIntsRequest
int64 a
int64 b
int64 sum
Create the service server with this message type and a callback function that calculates the addition.
For your convenience, the exampleHelperROS2SumCallback function already implements this
calculation. Specify the function as a callback.
sumserver = ros2svcserver(node_1,"/sum","example_interfaces/AddTwoInts",@exampleHelperROS2SumCall
sumserver =
ros2svcserver with properties:
ServiceType: 'example_interfaces/AddTwoInts'
ServiceName: '/sum'
NewRequestFcn: @exampleHelperROS2SumCallback
History: 'keeplast'
Depth: 10
Reliability: 'reliable'
Durability: 'volatile'
To call the service server, you have to create a service client. Note that this client can be created
anywhere in the ROS 2 network. For the purposes of this example, we will create a client for
the /sum service in MATLAB. Then we will wait to ensure the client has connected to the server.
sumclient = ros2svcclient(node_3,"/sum","example_interfaces/AddTwoInts")
sumclient =
ros2svcclient with properties:
ServiceType: 'example_interfaces/AddTwoInts'
ServiceName: '/sum'
History: 'keeplast'
Depth: 10
Reliability: 'reliable'
Durability: 'volatile'
waitForServer(sumclient,"Timeout",3);
2-46
Call and Provide ROS 2 Services
Create the request message. You can define the two integers, a and b, which are added together
when you use the call command.
sumreq = ros2message(sumclient);
sumreq.a = int64(2);
sumreq.b = int64(1);
The expectation is that the sum of these two numbers will be 3. To call the service, use the following
command. The service response message will contain a sum property, which stores the addition of a
and b.
sumresp = call(sumclient,sumreq,"Timeout",3)
Remove the sample nodes and service servers from the ROS 2 network.
clear("node_1");
clear("node_2");
clear("node_3");
Next Steps
• Refer to “Work with Basic ROS 2 Messages” on page 2-13 to explore how ROS 2 messages are
represented in MATLAB.
2-47
2 ROS 2 Featured Examples
The tf system in ROS 2 keeps track of multiple coordinate frames and maintains the relationship
between them in a tree structure. tf is distributed, so that all coordinate frame information is
available to every node in the ROS 2 network. MATLAB® enables you to access this transformation
tree. This example familiarizes you with accessing the available coordinate frames, retrieving
transformations between them, and transform points, vectors, and other entities between any two
coordinate frames.
node = ros2node("/matlabNode",25);
There are three coordinate frames that are defined in this transformation tree:
• the transformation from the robot base to the camera's mounting point
• the transformation from the mounting point to the center of the camera
exampleHelperROS2StartTfPublisher
2-48
Access the tf Transformation Tree in ROS 2
Here, the x, y, and z axes of each frame are represented by red, green, and blue lines respectively.
The parent-child relationship between the coordinate frames is shown through a brown arrow
pointing from the child to its parent frame.
Create a new transformation tree using ros2tf object. You can use this object to access all available
transformations and apply them to different entities.
tftree = ros2tf(node,...
"DynamicBroadcasterQoS", struct('Depth', 50), ...
"DynamicListenerQoS", struct('Reliability','besteffort'), ...
"StaticBroadcasterQoS", struct('Depth',10), ...
"StaticListenerQoS", struct('Durability','volatile'));
Once the object is created, it starts receiving tf transformations and buffers them internally. Keep the
tftree variable in the workspace so that it continues to receive data.
Pause for a little bit to make sure that all transformations are received.
pause(2);
You can see the names of all the available coordinate frames by accessing the AvailableFrames
property.
tftree.AvailableFrames
2-49
2 ROS 2 Featured Examples
This should show the three coordinate frames that describe the relationship between the camera, its
mounting point, and the robot.
Receive Transformations
Now that the transformations are available, you can inspect them. Any transformation is described by
a ROS 2 geometry_msgs/TransformStamped message and has a translational and rotational
component.
Retrieve the transformation that describes the relationship between the mounting point and the
camera center. Use the getTransform function to do that.
mountToCamera = getTransform(tftree, 'mounting_point', 'camera_center');
mountToCameraTranslation = mountToCamera.transform.translation
quat = mountToCamera.transform.rotation
mountToCameraRotationAngles = 1×3
0 90 0
Relative to the mounting point, the camera center is located 0.5 meters along the z-axis and is rotated
by 90 degrees around the y-axis.
To inspect the relationship between the robot base and the camera's mounting point, call
getTransform again.
baseToMount = getTransform(tftree, 'robot_base', 'mounting_point');
baseToMountTranslation = baseToMount.transform.translation
baseToMountRotation = baseToMount.transform.rotation
2-50
Access the tf Transformation Tree in ROS 2
x: 0
y: 0
z: 0
w: 1
The mounting point is located at 1 meter along the robot base's x-axis.
Apply Transformations
Assume now that you have a 3D point that is defined in the camera_center coordinate frame and
you want to calculate what the point coordinates in the robot_base frame are.
Use the getTransform function to wait until the transformation between the camera_center and
robot_base coordinate frames becomes available. This call blocks until the transformation that
takes data from camera_center to robot_base is valid and available in the transformation tree.
getTransform(tftree,'robot_base','camera_center','Timeout', Inf);
Now define a point at position [3 1.5 0.2] in the camera center's coordinate frame. You will
subsequently transform this point into robot_base coordinates.
pt = ros2message('geometry_msgs/PointStamped');
pt.header.frame_id = 'camera_center';
pt.point.x = 3;
pt.point.y = 1.5;
pt.point.z = 0.2;
You can transform the point coordinates by calling the transform function on the transformation
tree object. Specify what the target coordinate frame of this transformation is. In this example, use
robot_base.
tfpt = transform(tftree, 'robot_base', pt)
Besides PointStamped messages, the transform function allows you to transform other entities
like poses (geometry_msgs/PoseStamped), quaternions (geometry_msgs/QuaternionStamped),
and point clouds (sensor_msgs/PointCloud2).
If you want to store a transformation, you can retrieve it with the getTransform function.
robotToCamera = getTransform(tftree, 'robot_base', 'camera_center')
This transformation can be used to transform coordinates in the camera_center frame into
coordinates in the robot_base frame.
2-51
2 ROS 2 Featured Examples
robotToCamera.transform.translation
robotToCamera.transform.rotation
Send Transformations
Assume that you have a simple transformation that describes the offset of the wheel coordinate
frame relative to the robot_base coordinate frame. The wheel is mounted -0.2 meters along the y-
axis and -0.3 along the z-axis. The wheel has a relative rotation of 30 degrees around the y-axis.
tfStampedMsg = ros2message('geometry_msgs/TransformStamped');
tfStampedMsg.child_frame_id = 'wheel';
tfStampedMsg.header.frame_id = 'robot_base';
The transformation itself is described in the Transform property. It contains a Translation and a
Rotation. Fill in the values that are listed above.
The Rotation is described as a quaternion. To convert the 30 degree rotation around the y-axis to a
quaternion, you can use the axang2quat (Navigation Toolbox) function. The y-axis is described by
the [0 1 0] vector and 30 degrees can be converted to radians with the deg2rad function.
tfStampedMsg.transform.translation.x = 0;
tfStampedMsg.transform.translation.y = -0.2;
tfStampedMsg.transform.translation.z = -0.3;
Use ros2time to retrieve the current system time and use that to timestamp the transformation.
This lets the recipients know at which point in time this transformation was valid.
tfStampedMsg.header.stamp = ros2time(node,'now');
2-52
Access the tf Transformation Tree in ROS 2
sendTransform(tftree, tfStampedMsg)
The new wheel coordinate frame is now also in the list of available coordinate frames.
tftree.AvailableFrames
The final visual representation of all four coordinate frames looks as follows.
You can see that the wheel coordinate frame has the translation and rotation that you specified in
sending the transformation.
exampleHelperROS2StopTfPublisher
2-53
2 ROS 2 Featured Examples
clear('node')
See Also
Related Examples
• “Read and Apply Transformation to ROS 2 Message in Simulink” on page 7-43
2-54
Using ROS Bridge to Establish Communication Between ROS and ROS 2
ROS 2 is newer version of ROS with different architecture. Both the networks are separate and there
is no direct communication between the nodes in ROS and ROS 2. The ros1_bridge package
provides a network bridge which enables the exchange of messages between ROS and ROS 2. The
bridge manages all the conversion required and sends messages across both the networks. For more
information, see ros1_bridge. This example uses a virtual machine which may be downloaded by
following the instructions in “Get Started with Gazebo and Simulated TurtleBot” on page 1-205. The
ros1_bridge package is installed on this virtual machine.
This example shows how to control the TurtleBot3 in Gazebo using keyboard commands from the
MATLAB®. The Gazebo Simulator is available in ROS 1 networks only. You can use ros1_bridge to
exchange the Gazebo topics such as '/odom' or '/cmd_vel' to ROS 2.
The below diagram depicts the message exchange between ROS 1 and ROS 2 networks using
ros1_bridge. The '/odom' topic contains nav_msgs/Odometry messages sent from the ROS 1
network with Gazebo. The ROS 2 node subscribes to the /odom topic that has been bridged from ROS
1 and publishes a '/cmd_vel' message based on the robot pose. The bridge then takes the '/
cmd_vel' message and publishes it on the ROS 1 network.
2-55
2 ROS 2 Featured Examples
Prerequisites:
• Download the Virtual Machine using instructions in “Get Started with Gazebo and Simulated
TurtleBot” on page 1-205
• “Connect to a ROS 2 Network” on page 2-8
Open the DEFAULT_FASTRTPS_PROFILE.xml file in the home directory of the VM and replace
<address> entries with host and VM IP addresses. To communicate under different subnets (see
Communicate Outside Subnet section in “Connect to a ROS 2 Network” on page 2-8).
Launch Gazebo
On the VM desktop, click Gazebo Empty. This Gazebo world contains a Turtlebot robot, which
publishes and subscribes to messages on a ROS 1 network.
2-56
Using ROS Bridge to Establish Communication Between ROS and ROS 2
Click the ROS Bridge shortcut. This bridge setups publishers and subscribers for all the ROS 1
topics on a ROS 2 network.
2-57
2 ROS 2 Featured Examples
2-58
Using ROS Bridge to Establish Communication Between ROS and ROS 2
2-59
2 ROS 2 Featured Examples
2-60
Using ROS Bridge to Establish Communication Between ROS and ROS 2
In MATLAB on your host machine, set the proper domain ID for the ROS 2 network using the
'ROS_DOMAIN_ID' environment variable to 25 to match the robot simulator ROS bridge settings and
run ros2 topic list to verify that the topics from the robot simulator are visible in MATLAB.
setenv("ROS_DOMAIN_ID","25");
ros2 topic list
/clock
/gazebo/link_states
/gazebo/model_states
/gazebo/performance_metrics
/imu
/joint_states
/odom
/parameter_events
/rosout
/rosout_agg
/scan
/tf
Create a ROS 2 node. Subscribe to the odometry topic that is bridged from ROS 1.
ros2Node = ros2node("/example_node");
handles.odomSub = ros2subscriber(ros2Node,"/odom","nav_msgs/Odometry")
Receive the odometry messages from the bridge and use the exampleHelperGet2DPose function to
unpack the message into a 2D pose. Get the start position of the robot.
odomMsg = receive(handles.odomSub);
poseStart = exampleHelperGet2DPose(odomMsg)
poseStart = 1×3
10-3 ×
handles.poses = poseStart;
Create a publisher for controlling the robot velocity. The bridge takes these messages and sends them
on the ROS 1 network.
handles.velPub = ros2publisher(ros2Node,'/cmd_vel','geometry_msgs/Twist')
2-61
2 ROS 2 Featured Examples
based on the keyboard inputs. The bridge transfers those messages to the ROS 1 network for the
Gazebo simulator.
poses = exampleHelperROS2TurtleBotKeyboardControl(handles);
The figure that opens listens to keyboard inputs for controlling the robot in Gazebo. Hit the keys and
watch the robot move. Press Q to exit.
2-62
Using ROS Bridge to Establish Communication Between ROS and ROS 2
Plot the results to show how TurtleBot3 moved in Gazebo. The poses variable has stored all the
updated /odom messages that were received from the ROS 1 network.
2-63
2 ROS 2 Featured Examples
odomMsg = receive(handles.odomSub);
poseEnd = exampleHelperGet2DPose(odomMsg)
poseEnd = 1×3
poses = [poses;poseEnd];
figure
plot(poses(:,1),poses(:,2),'b-', ...
poseStart(1),poseStart(2),'go', ...
poseEnd(1),poseEnd(2),'ro');
xlabel('X [m]');
ylabel('Y [m]');
legend('Trajectory','Start','End');
clear
2-64
Get Started with ROS 2 in Simulink
This example shows how to use Simulink® blocks for ROS 2 to send and receive messages from a
local ROS 2 network.
Introduction
Simulink support for Robot Operating System 2 (ROS 2) enables you to create Simulink models that
work with a ROS 2 network. ROS 2 is a communication layer that allows different components of a
robot system to exchange information in the form of messages. A component sends a message by
publishing it to a particular topic, such as /odometry. Other components receive the message by
subscribing to that topic.
Simulink support for ROS 2 includes a library of Simulink blocks for sending and receiving messages
for a designated topic. When you simulate the model, Simulink connects to a ROS 2 network, which
can be running on the same machine as Simulink or on a remote system. Once this connection is
established, Simulink exchanges messages with the ROS 2 network until the simulation is terminated.
If Simulink Coder™ is installed, you can also generate C++ code for a standalone ROS 2 node, from
the Simulink model.
• Create and run a Simulink model to send and receive ROS 2 messages
• Work with data in ROS 2 messages
Prerequisites: Create a Simple Model, “Get Started with ROS 2” on page 2-2
Model
You will use Simulink to publish the X and Y location of a robot. You will also subscribe to the same
location topic and display the received X,Y location.
Enter the following command to open the completed model created in example.
open_system('ros2GetStartedExample');
Create a Publisher
Configure a block to send a geometry_msgs/Point message to a topic named /location (the "/"
is standard ROS syntax).
• From the MATLAB Toolstrip, select Home > New > Simulink Model to open a new Simulink
model.
• From the Simulink Toolstrip, select Simulation > Library Browser to open the Simulink Library
Browser. Click on the ROS Toolbox tab (you can also type roslib in MATLAB command window).
Select the ROS 2 Library.
• Drag a Publish block to the model. Double-click on the block to configure the topic and message
type.
• Select Specify your own for the Topic source, and enter /location in Topic.
• Click Select next to Message type. A pop-up window will appear. Select geometry_msgs/Point
and click OK to close the pop-up window.
2-65
2 ROS 2 Featured Examples
• You can also specify the ROS 2 Domain ID by clicking Configure ROS 2 Domain ID and ROS
Middleware (RMW) option.
2-66
Get Started with ROS 2 in Simulink
2-67
2 ROS 2 Featured Examples
Create a blank ROS 2 message and populate it with the x and y location for the robot path. Then
publish the updated ROS 2 message to the ROS 2 network.
A ROS 2 message is represented as a bus signal in Simulink. A bus signal is a bundle of Simulink
signals, and can also include other bus signals (see the “Explore Simulink Bus Capabilities”
(Simulink) example for an overview). The ROS 2 Blank Message block outputs a Simulink bus signal
corresponding to a ROS 2 message.
• Click ROS Toolbox tab in the Library Browser, or type roslib at the MATLAB command line.
Select the ROS 2 Library.
• Drag a Blank Message block to the model. Double-click on the block to open the block mask.
• Click on Select next to the Message type box, and select geometry_msgs/Point from the
resulting pop-up window. set Sample time to 0.01. Click OK to close the block mask.
• From the Simulink > Signal Routing tab in the Library Browser, drag a Bus Assignment block.
• Connect the output port of the Blank Message block to the Bus input port of the Bus
Assignment block. Connect the output port of the Bus Assignment block to the input port of
Publish block.
• Double-click on the Bus Assignment block. You should see x, y and z (the signals comprising a
geometry_msgs/Point message) listed on the left. Select ??? signal1 in the right listbox and
click Remove. Select both X and Y signals in the left listbox and click Select. Click OK to apply
changes.
NOTE: If you do not see x, y and z listed, close the block mask for the Bus Assignment block, and
under the Modeling tab, click Update Model to ensure that the bus information is correctly
propagated. If you see the error, "Selected signal 'signal1' in the Bus Assignment block cannot be
found", it indicates that the bus information has not been propagated. Close the Diagnostic Viewer,
and repeat the above step.
You can now populate the bus signal with the robot location.
• From the Simulink > Sources tab in the Library Browser, drag two Sine Wave blocks into the
model.
• Connect the output ports of each Sine Wave block to the assignment input ports x and y of the
Bus Assignment block.
• Double-click on the Sine Wave block that is connected to input port X. Set the Phase parameter
to -pi/2 and click OK. Leave the Sine Wave block connected to input port Y as default.
2-68
Get Started with ROS 2 in Simulink
At this point, the model is set up to publish messages to the ROS 2 network. You can verify this as
follows:
• Under the Simulation tab, set the simulation stop time to inf.
• Click Run to start simulation. Simulink creates a dedicated ROS 2 node for the model and a ROS 2
publisher corresponding to the Publish block.
• While the simulation is running, type ros2 node list in the MATLAB command window. This
lists all the nodes available in the ROS network, and includes a node with a name like /
untitled_90580 (the name of the model along with a random number to make it unique).
• While the simulation is running, type ros2 topic list in the MATLAB command window. This
lists all the topics available in the ROS 2 network, and it includes /location.
• If you specified a ROS 2 domain ID in the Publish block, to list all the topics, type ros2 topic
list domainID xx, where xx is the domain ID you specified.
• Click Stop to stop the simulation. Simulink deletes the ROS 2 node and publisher. In general, the
ROS 2 node for a model and any associated publishers and subscribers are automatically deleted
at the end of a simulation; no additional clean-up steps are required.
Create a Subscriber
Use Simulink to receive messages sent to the /location topic. You will extract the x and y location
from the message and plot it in the xy-plane.
• From the ROS Toolbox tab in the Library Browser, drag a Subscribe block to the model. Double-
click on the block.
2-69
2 ROS 2 Featured Examples
• Select Specify your own in the Topic source box, and enter /location in the Topic box.
• Click Select next to the Message type box, and select geometry_msgs/Point from the pop-up
window. set Sample time to 0.01. Click OK to close the block mask.
The Subscribe block outputs a Simulink bus signal, so you need to extract the x and y signals from it.
• From the Simulink > Signal Routing tab in the Library Browser, drag a Bus Selector block to
the model.
• Connect the Msg output of the Subscribe block to the input port of the Bus Selector block.
• From the Modeling tab, select Update Model to ensure that the bus information is propagated.
You may get errors and they will be resolved by the next step.
• Double-click on the Bus Selector block. Select signal1 and signal2 in the right listbox and
click to remove them. Select both x and y signals in the left listbox and click to select
the signals. Click OK.
The Subscribe block will output the most-recently received message for the topic on every time step.
The IsNew output indicates whether the message has been received during the prior time step. For
the current task, the IsNew output is not needed, so do the following:
• From the Simulink > Sinks tab in the Library Browser, drag a Terminator block to the model.
• Connect the IsNew output of the Subscribe block to the input of the Terminator block.
The remaining steps configure the display of the extracted X and Y signals.
• From the Simulink > Sinks tab in the Library Browser, drag an XY Graph block to the model.
Connect the output ports of the Bus Selector block to the input ports of the XY Graph block.
• From the Simulink > Sinks tab in the Library Browser, drag two Display blocks to the model.
Connect each output of the Bus Selector block to each Display block.
• Save your model.
2-70
Get Started with ROS 2 in Simulink
• From the Modeling tab, select Model Settings. In the Solver pane, set Type to Fixed-step and
Fixed-step size to 0.01.
• Set simulation stop time to 10.0.
• Click Run to start simulation. An XY plot will appear.
2-71
2 ROS 2 Featured Examples
The first time you run the model in Simulink, the XY plot may look more jittery than the one above
due to delays caused by loading ROS libraries. Once you rerun the simulation a few times, the plot
should look smoother.
Note that the simulation does not work in actual or "real" time. The blocks in the model are
evaluated in a loop that only simulates the progression of time, and is not intended to track actual
clock time (for details, see “Simulation Loop Phase” (Simulink)).
In the above model, the Subscribe block outputs a message (bus signal) on every time step; if no
messages have been received at all, it outputs a blank message (i.e., a message with zero values).
Consequently, the XY coordinates are initially plotted at (0,0).
In this task, you will modify the model to use an Enabled Subsystem, so that it plots the location
only when a new message is received (for more information, see “Using Enabled Subsystems”
(Simulink)). A pre-configured model is included for your convenience.
• In the model, click and drag to select the Bus Selector block and XY Graph blocks. Right-click
on the selection and select Create Subsystem from Selection.
• From the Simulink > Ports & Subsystems tab in the Library Browser, drag an Enable block
into the newly-created subsystem.
• Connect the IsNew output of the Subscribe block to the enabled input of the subsystem as shown
in the picture below. Delete the Terminator block. Note that the IsNew output is true only if a
new message was received during the previous time step.
2-72
Get Started with ROS 2 in Simulink
The blocks in the enabled subsystem are only executed when a new ROS 2 message is received by the
Subscribe block. Hence, the initial (0,0) value will not be displayed in the XY plot.
2-73
2 ROS 2 Featured Examples
This example shows you how to configure a Simulink® model to send and receive information from a
separate ROS-based simulator such as Gazebo® over ROS 2.
Introduction
You can use Simulink to connect to a ROS-enabled physical robot or to a ROS-enabled robot simulator
such as Gazebo. This example shows how to:
Prerequisites
In this task, you will start a ROS-based simulator for a differential-drive robot along with a ROS
bridge that replays ROS messages over ROS 2 network.
• Download a virtual machine using the instructions in “Get Started with Gazebo and Simulated
TurtleBot” on page 1-205.
• Open the DEFAULT_FASTRTPS_PROFILE.xml file in the home directory of the VM and replace
<address> entries with host and VM IP addresses. To communicate under different subnets (see
Communicate Outside Subnet section in “Connect to a ROS 2 Network” on page 2-8).
2-74
Connect to a ROS-Enabled Robot from Simulink over ROS 2
• In the Ubuntu desktop, click the "Gazebo Empty" icon to start the Gazebo world.
• Click on the "ROS Bridge" icon, to relay messages between ROS and ROS 2 network.
2-75
2 ROS 2 Featured Examples
• In MATLAB on your host machine, set the proper domain ID for the ROS 2 network using the
'ROS_DOMAIN_ID' environment variable to 25 to match the robot simulator ROS bridge settings
and run ros2 topic list to verify that the topics from the robot simulator are visible in
MATLAB.
setenv('ROS_DOMAIN_ID','25')
ros2 topic list
/clock
/gazebo/link_states
/gazebo/model_states
/gazebo/performance_metrics
/imu
/joint_states
/odom
/parameter_events
/rosout
/rosout_agg
/scan
/tf
2-76
Connect to a ROS-Enabled Robot from Simulink over ROS 2
open_system('robotROS2ConnectToRobotExample');
• From the Simulation tab Prepare gallery, click ROS Network under ROS TOOLBOX.
• In the Configure ROS Network Addresses dialog, under Domain ID (ROS 2), set ID to 25.
This ID value matches the domain ID of the ROS 2 network on the Ubuntu virtual machine, where
the messages from Gazebo in ROS network are received.
2-77
2 ROS 2 Featured Examples
Create a publisher that sends control commands (linear and angular velocities) to the simulator.
Make these velocities adjustable by using Slider Gain blocks.
2-78
Connect to a ROS-Enabled Robot from Simulink over ROS 2
ROS uses a right-handed coordinate system, so X-axis is forward, Y-axis is left and Z-axis is up.
Control commands are sent using a geometry_msgs/Twist message, where linear.x indicates
linear forward velocity (in meters/sec), and angular.z indicates angular velocity around the Z-axis
(in radians/sec).
2-79
2 ROS 2 Featured Examples
• Set the limits, and current parameters of the linear velocity slider to 0.0 to 2.0, and 1.0
respectively. Set the corresponding parameters of the steering gain slider to -1.0 to 1.0, and
0.1.
Create a subscriber to receive messages sent to the /odom topic. You will also extract the location of
the robot and plot it's path in the XY-plane.
• From the ROS Toolbox > ROS 2 tab in the Library Browser, drag a Subscribe block to the
model. Double-click the block.
• Set Topic source to Select From ROS network, and click Select next to the Topic box. Select "/
odom" for the topic and click OK. Note that the message type nav_msgs/Odometry is set
automatically.
• From the Simulink > Signal Routing tab in the Library Browser, drag a Bus Selector block to
the model.
• Connect the Msg output port of the Subscribe block to the input port of the Bus Selector block.
In the Modeling tab, click Update Model to ensure that the bus information is correctly
propagated.
• Double-click the Bus Selector block. Select signal1 and signal2 in the right listbox and click
to remove them. In the left listbox, expand pose > pose > position and select x and y. Click
The following figure shows the completed model. A pre-configured model is included for your
convenience.
2-80
Connect to a ROS-Enabled Robot from Simulink over ROS 2
• From the Modeling tab, click Model Settings. In the Solver pane, set Type to Fixed-step and
Fixed-step size to 0.01.
• Set simulation Stop time to inf.
• Click Run to start the simulation.
• In both the simulator and XY plot, you should see the robot moving in a circle.
• While the simulation is running, change the values of Slider Gain blocks to control the robot.
Double-click the XY Graph block and change the X and Y axis limits if needed (you can do this
while the simulation is running).
• To stop the simulation, click Stop.
2-81
2 ROS 2 Featured Examples
This example shows you how to use Simulink® to control a simulated robot running in a Gazebo®
robot simulator over ROS 2 network.
Introduction
In this example, you will run a model that implements a simple closed-loop proportional controller.
The controller receives location information from a simulated robot and sends velocity commands to
drive the robot to a specified location. You will adjust some parameters while the model is running
and observe the effect on the simulated robot.
The following diagram summarizes the interaction between Simulink and the robot simulator (the
arrows in the diagram indicate ROS 2 message transmission). The /odom topic conveys location
information, and the /cmd_vel topic conveys velocity commands.
In this task, you will start a ROS-based simulator for a differential-drive robot, start the ROS bridge
configure MATLAB® connection with the robot simulator.
• Download a virtual machine using the instructions in “Get Started with Gazebo and Simulated
TurtleBot” on page 1-205.
• Open the DEFAULT_FASTRTPS_PROFILE.xml file in the home directory of the VM and replace
<address> entries with host and VM IP addresses. To communicate under different subnets, see
Communicate Outside Subnet section in “Connect to a ROS 2 Network” on page 2-8.
2-82
Feedback Control of a ROS-Enabled Robot Over ROS 2
• In the Ubuntu desktop, click the Gazebo Empty icon to start the empty Gazebo world.
2-83
2 ROS 2 Featured Examples
2-84
Feedback Control of a ROS-Enabled Robot Over ROS 2
• Click the ROS Bridge icon to start the ROS bridge to relay messages between Simulink ROS 2
node and Turtlebot3 ROS-enabled robot.
• In MATLAB on your host machine, set the proper domain ID for the ROS 2 network using the
'ROS_DOMAIN_ID' environment variable to 25 to match the robot simulator ROS bridge settings
and run ros2 topic list to verify that the topics from the robot simulator are visible in
MATLAB.
setenv('ROS_DOMAIN_ID','25')
ros2 topic list
/clock
/gazebo/link_states
/gazebo/model_states
/gazebo/performance_metrics
/imu
/joint_states
/odom
/parameter_events
/rosout
/rosout_agg
/scan
/tf
open_system('robotROS2FeedbackControlExample.slx');
2-85
2 ROS 2 Featured Examples
The model implements a proportional controller for a differential-drive mobile robot. On each time
step, the algorithm orients the robot toward the desired location and drives it forward. Once the
desired location is reached, the algorithm stops the robot.
open_system('robotROS2FeedbackControlExample/Proportional Controller');
2-86
Feedback Control of a ROS-Enabled Robot Over ROS 2
Note that there are four tunable parameters in the model (indicated by colored blocks).
• Desired Position (at top level of model): The desired location in (X,Y) coordinates
• Distance Threshold: The robot is stopped if it is closer than this distance from the desired
location
• Linear Velocity: The forward linear velocity of the robot
• Gain: The proportional gain when correcting the robot orientation
The model also has a Simulation Rate Control block (at top level of model). This block ensures that
the simulation update intervals follow wall-clock elapsed time.
In this task, you will configure Simulink to communicate with ROS-enabled robot simulator over ROS
2, run the model and observe the behavior of the robot in the robot simulator.
• Under the Simulation tab, in PREPARE, select ROS Toolbox > ROS Network.
• In Configure ROS Network Addresses, set the ROS 2 Domain ID value to 25 and set the ROS 2
RMW Implementation as rmw_fastrtps_cpp.
• Click OK to apply changes and close the dialog.
2-87
2 ROS 2 Featured Examples
• Position windows on your screen so that you can observe both the Simulink model and the robot
simulator.
• Click the Play button in Simulink to start simulation.
2-88
Feedback Control of a ROS-Enabled Robot Over ROS 2
• While the simulation is running, double-click on the Desired Position block and change the
Constant value to [2 3]. Observe that the robot changes its heading.
• While the simulation is running, open the Proportional Controller subsystem and double-click
on the Linear Velocity (slider) block. Move the slider to 2. Observe the increase in robot
velocity.
• Click the Stop button in Simulink to stop the simulation.
In this task, you will observe the timing and rate of incoming messages.
The synchronization with wall-clock time is due to the Simulation Rate Control block. Typically, a
Simulink simulation executes in a free-running loop whose speed depends on complexity of the model
and computer speed (see Simulation Loop Phase (Simulink)). The Simulation Rate Control block
attempts to regulate Simulink execution so that each update takes 0.02 seconds in wall-clock time
when possible (this is equal to the fundamental sample time of the model). See the comments inside
the block for more information.
In addition, the Enabled subsystems for the Proportional Controller and the Command Velocity
Publisher ensure that the model only reacts to genuinely new messages. If enabled subsystems were
not used, the model would repeatedly process the same (most-recently received) message over and
over, leading to wasteful processing and redundant publishing of command messages.
2-89
2 ROS 2 Featured Examples
Summary
This example showed you how to use Simulink for simple closed-loop control of a simulated robot. It
also showed how to use Enabled subsystems to reduce overhead in the ROS 2 network.
2-90
Publish and Subscribe to ROS 2 Messages in Simulink
This model shows how to publish and subscribe to a ROS 2 topic using Simulink®.
Use the Blank Message and Bus Assignment blocks to specify the x and y values of a
'geometry_msgs/Point' message type. Open the Blank Message block mask to specify the
message type. set Sample time to 0.01. Open the Bus Assignment block mask to select the signals you
want to assign. Remove any values with '???' from the right column. Supply the Bus Assignment
block with relevant values for x and y.
Feed the Bus output to the Publish block. Open the block mask and choose Specify your own as
the topic source. Specify the topic, '/location', and message type, 'geoemetry_msgs/Point'.
Set Sample time to 0.01.
Add a Subscribe block and specify the topic and message type. Feed the output Msg to a Bus Selector
and specify the selected signals in the block mask. Display the x and y values.
Set the simulation stop time to Inf and run the model. You should see the xPosition_Out and
yPosition_Out displays show the corresponding values published to the ROS 2 network.
2-91
2 ROS 2 Featured Examples
2-92
Generate a Standalone ROS 2 Node from Simulink
This example shows you how to generate and build a standalone ROS 2 node from a Simulink®
model. You configure a model to generate C++ code for a standalone ROS 2 node. Then, build and
run the ROS 2 node on your host computer.
Prerequisites
Configure a model to generate C++ code for a standalone ROS 2 node. The model is the proportional
controller introduced in the “Feedback Control of a ROS-Enabled Robot Over ROS 2” on page 2-82
example.
• Open the robot feedback control model configured for ROS 2. Alternatively, call
open_system("robotControllerROS2").
• Under ROS tab, in Prepare, click Hardware settings. In the Hardware implementation pane,
Hardware board settings section contains settings specific to the generated ROS 2 package,
such as information to be included in the package.xml file. Change Maintainer name to ROS 2
Example User.
• The model requires variable-sized arrays. To enable this option, check variable-size signals
under Code Generation > Interface > Software environment.
• In the Solver pane, ensure that Solver Type is set to Fixed-step, and set Fixed-step size to
0.05. In generated code, the Fixed-step size defines the actual time step, in seconds, that is used
for the model update loop (see “Execution of Code Generated from a Model” (Simulink Coder)). It
can be made smaller (e.g., 0.001 or 0.0001) but for current purposes 0.05 is sufficient.
• Specify external ROS packages as dependencies: To specify external ROS 2 packages as
dependencies to the generated ROS 2 node, specify appropriate toolchain options. In the
Configuration parameters, under Code Generation > Toolchain Settings, specify the Build
configuration as Specify from the drop-down. Then, you can specify the Required Packages,
Include Directories, Link Libraries, Library Paths and Defines based on the external ROS 2
packages that you wish to integrate with the generated ROS 2 node.
• Click OK.
A ROS 2 device is any Linux system that has ROS 2 installed and is capable of building and running
a ROS 2 node. If you have Simulink Coder, you can generate code for a standalone ROS 2 node. If
your system is connected to a ROS 2 device, Simulink can also transfer the generated code to the
ROS 2 device, build an executable, and run the resulting ROS 2 node (this is referred to as
"deploying" the ROS node).
2-93
2 ROS 2 Featured Examples
In this task, you decide if you want to generate code for the ROS 2 node or if you want to build and
run it on a ROS 2 device. If you are connected to a ROS 2 device, you can configure Simulink to use it
as a deployment target for your ROS 2 node.
ROS 2 Folder is the location of the ROS 2 installation on the ROS 2 device. If you do not specify this
folder, the settings test (see next step) tries to determine the correct folder for you.
2-94
Generate a Standalone ROS 2 Node from Simulink
• If the ROS 2 device is turned on and accessible from your computer, you can verify the connection
settings by clicking Test. The test verifies every device setting and display warnings and errors in
the Simulink Diagnostic Viewer if problems are found. If possible, the test also suggests how the
problems can be fixed. Click Test now.
• Most likely, the Catkin workspace ~/ros2_ws_test does not exist on the target device. The test
detects this problem and suggests to create the folder and initialize the workspace. Click Fix to
apply this action automatically. After a few seconds, you should see a green notice that the folder
has been created successfully. In the following figure you can see an example of creating the
folder successfully. To verify that the Catkin workspace is now available, click Test in the
connection settings dialog again. The warning has disappeared and the Catkin workspace is ready
to build your ROS 2 node.
2-95
2 ROS 2 Featured Examples
• Change the device connection settings and test them until no other warnings or errors are shown.
If an automatic fix to your settings is possible, Simulink suggests it by displaying the Fix button.
Once you have a good set of settings, click OK in the connection settings dialog to save the
settings.
The connection settings are not specific to a single model, but apply to all ROS 2 models in
Simulink.
In this task, you generate code for a standalone ROS 2 node, and automatically build, and run it on
the host computer.
• In MATLAB®, change the current folder to a location where you have write permission.
• Under the Simulation tab, in Prepare, select ROS Toolbox > ROS Network.
• Set the Domain ID (ROS 2) of ROS 2 network. This example uses Domain ID as 25.
• If you are deploying to a local device, set the environment variable ROS_DOMAIN_ID to the value
25, using setenv in MATLAB.
• Set the ROS Middleware (ROS 2) of ROS 2 network. This example uses ROS Middleware as
rmw_cyclonedds_cpp.
• If you are deploying to a local device, set the environment variable RMW_IMPLEMENTATION to
rmw_cyclonedds_cpp, using setenv in MATLAB.
• In ROS tab, from the Deploy section dropdown, click Build & Run. If you get any errors about
bus type mismatch, close the model, clear all variables from the base MATLAB workspace, and re-
open the model. Click on the View Diagnostics link at the bottom of the model toolbar to see the
output of the build process.
Once the code generation completes, the ROS 2 node builds in the present working folder starts to
run automatically in a synchronous fashion based on the sample time of the model. When running in
Windows®, a Command window opens. Do not close the window, but use Ctrl+C to shutdown the
ROS 2 node.
2-96
Generate a Standalone ROS 2 Node from Simulink
Use ros2 node to list all running nodes is the ROS 2 network. robotControllerROS2 should be in
the displayed list of nodes.
ros2('node','list')
/robotControllerROS2
/ros_bridge
Verify that the deployed node publishes data on the ROS 2 topic, /cmd_vel, to control the motion of
simulated robot.
ros2('topic','list')
/clock
/cmd_vel
/gazebo/link_states
/gazebo/model_states
/imu
/joint_states
/odom
/parameter_events
/rosout
/rosout_agg
/scan
/tf
You can choose different code generation and build behaviors by specifying one of these Deployment
options from the toolstrip under ROS tab.
• Generate code — Generates the ROS package source code on localhost or remote device.
• Build Model — Generates the ROS package source code and builds the standalone executable on
localhost or remote device.
• Build & Run — Generates the ROS package source code, builds the standalone executable and
starts running it on localhost or remote device.
2-97
2 ROS 2 Featured Examples
This example shows you how to generate C++ code from a Simulink® model to deploy as a
standalone ROS 2 node. The code is generated on your computer and must be manually transferred
to the target ROS device. No connection to the hardware is necessary for generated the code. For an
automated deployment of a ROS 2 node, see “Generate a Standalone ROS 2 Node from Simulink” on
page 2-93.
Prerequisites
Configure a model to generate C++ code for a standalone ROS 2 node. The model is the proportional
controller introduced in the “Feedback Control of a ROS-Enabled Robot Over ROS 2” on page 2-82
example.
open_system("robotFeedbackControllerROS2");
• Under ROS tab, click Hardware settings. In the Hardware implementation pane, Hardware
board settings section contains settings specific to the generated ROS 2 package, such as
information to be included in the package.xml file. Change Maintainer name to ROS 2
Example User, click Apply.
• The model requires variable-sized arrays. To enable this option, check variable-size signals
under Code Generation > Interface > Software environment.
• In the Solver pane, ensure that the solver Type is set to Fixed-step, and set Fixed-step size to
0.05. In generated code, the Fixed-step size defines the actual time step, in seconds, that is used
for the model update loop (see “Execution of Code Generated from a Model” (Simulink Coder)
(Simulink Coder)). It can be made smaller (e.g., 0.001 or 0.0001) but for current purposes 0.05 is
sufficient.
• Click OK.
After configuring the model, you must specify the build options for the target hardware and set the
folder or building the generated code.
Open the Configuration Parameters dialog. Under the Modeling tab, click Model Settings.
2-98
Generate Code to Manually Deploy a ROS 2 Node from Simulink
In the Hardware Implementation tab, under Target hardware resources, click the Build options
group. Set the Build action to Build. This setting ensures that code generated for the ROS 2 node
without building it on an external ROS 2 device.
In this task, you generate source code for ROS 2 node, manually deploy to Ubuntu Linux system, and
build it on the Linux system.
• In MATLAB®, change the current folder to a location where you have write permission.
• Under the Simulation tab, in Prepare, select ROS Toolbox > ROS Network.
• Set the Domain ID (ROS 2) of ROS 2 network. This example uses Domain ID as 25.
• In ROS tab, from the Deploy section, click Build Model. If you get any errors about bus type
mismatch, close the model, clear all variables from the base MATLAB workspace, and re-open the
model. Click on the View Diagnostics link at the bottom of the model toolbar to see the output of
the build process.
Once the build completes, a src folder which contains the package source code will be written to
your folder.
Compress the src folder to a tar file by executing the following command in MATLAB Command
Window:
>> tar('src.tar','src');
After generating the tar file, manually transfer it to the target machine. This example assumes you
are using the virtual machine from “Get Started with Gazebo and Simulated TurtleBot” on page 1-
205. The virtual machine is configured to accept SSH and SCP connections. If you are using your own
Linux system, consult your system administrator for a secure way to transfer files.
Ensure your host system (the system with your src.tar file) has an SCP client. For Windows®
systems, the next step assumes that PuTTY SCP client (pcsp.exe) is installed.
Use SCP to transfer the files to the user home director on the Linux virtual machine. Username is
user and password is password. Replace <virtual_machine_ip> with your virtual machines IP
address.
2-99
2 ROS 2 Featured Examples
On the Linux system, execute the following commands to create a ROS 2 workspace and decompress
the source code. You may use an existing ROS 2 workspace.
mkdir ~/ros2_ws_simulink
tar -C ~/ros2_ws_simulink/ -xvf ~/src.tar
Build the ROS 2 node using the following command in Linux. Replace <path_to_ros2_ws> with the
path to your ROS 2 workspace. In this example, the <path_to_ros2_ws> would be ~/
ros2_ws_simulink. (Note: There might be some warnings such as unused parameters during the
build process. These parameters are needed only for Simulink environment, it would not affect the
build process). If the node uses custom messages, you must manually copy the necessary custom
message packages in <path_to_ros2_ws>/msg folder before building the node.
cd <path_to_ros2_ws>
source /opt/ros/foxy/local_setup.sh
colcon build
file ~/ros2_ws_simulink/install/robotfeedbackcontrollerros2/lib/robotfeedbackcontrollerros2/robot
If the executable was created successfully, the command lists information about the file. The model is
now ready to be run as a standalone ROS 2 node on your device.
(Optional) You can then run the node using these commands. Replace <path_to_ros2_ws> with
the path to your ROS 2 workspace.
Double click Gazebo Empty and ROS Bridge on virtual machine desktop to set up the Gazebo
environment. Setup environment variables and run the ROS 2 node using:
export ROS_DOMAIN_ID=25
source /opt/ros/foxy/local_setup.sh
~/<path_to_ros2_ws>/install/robotfeedbackcontrollerros2/lib/robotfeedbackcontrollerros2/robotFeed
Note: It is possible that the robot spins at an unexpected location, this is because the pose and world
is offset in Gazebo. Restart virtual machine and rerun Gazebo and the node.
You can also use ros2 node to list all running nodes in the ROS 2 network.
robotFeedbackControllerROS2 should be in the displayed list of nodes.
ros2('node','list')
Verify that this ROS 2 node publishes data on the ROS 2 topic, /cmd_vel, to control the motion of
simulated robot.
ros2('topic','list')
If you cannot see the expected node and topic, try to set ROS_DOMAIN_ID using the setenv
command in MATLAB Command Window.
2-100
Generate Code to Manually Deploy a ROS 2 Node from Simulink
setenv("ROS_DOMAIN_ID","25")
2-101
2 ROS 2 Featured Examples
This example shows how to control a simulated robot running on a ROS-based simulator over a ROS
network. You generate a ROS node for the control algorithm and deploy it to the remote device
running ROS. The example shown here uses ROS and MATLAB for simulation, and MATLAB Coder™
for code generation and deployment. For the other examples with ROS 2 or Simulink®, see:
In this example, you implement a sign-following algorithm and control the simulated robot to follow a
path based on signs in the environment. The algorithm receives the location and camera information
from the simulated robot. The algorithm detects the color of the sign and sends velocity commands to
turn the robot based on the color. In this example, the robot turns left when it encounters a blue sign
and right when it encounters a green sign. The robot stops when it encounters a red sign.
Start a ROS-based simulator for a differential-drive robot and configure a MATLAB® connection with
the robot simulator.
Download a virtual machine using instructions in “Get Started with Gazebo and Simulated TurtleBot”
on page 1-205, then follow these steps.
masterIP = '172.18.228.122';
rosinit(masterIP,11311);
Create publishers and subscribers to relay messages to and from the robot simulator over ROS
network. You need subscribers for the image and odometry data. To control the robot, set up a
publisher to send velocity commands using /cmd_vel. The rossubscriber and rospublisher
functions support code generation for message structures only. To return a message structure, specify
the name-value pair argument, "DataFormat","struct", when creating subscribers and
publishers.
Create a rosbagwriter object to log the subscribed image and odometry data that the robot
publishes.
2-102
Sign Following Robot with ROS in MATLAB
bagWriter = rosbagwriter("sign_following_data.bag")
bagWriter =
rosbagwriter with properties:
FilePath: 'Z:\32\psahu.Bdoc23a.j2115093\sign_following_data.bag'
StartTime: 0
EndTime: 0
NumMessages: 0
Compression: 'uncompressed'
ChunkSize: 786432 Bytes
FileSize: 4117 Bytes
Define the image processing color threshold parameters. Each row defines the threshold values for
the corresponding color.
This example provides a helper MATLAB Stateflow® chart that takes as inputs the image size,
coordinates from a processed image, and robot odometry poses. The chart returns the linear and
angular velocity to drive the robot.
controller = ExampleHelperSignFollowingControllerChart;
open("ExampleHelperSignFollowingControllerChart");
2-103
2 ROS 2 Featured Examples
Run the controller to receive images and move the robot to follow the sign. The controller performs
these steps:
• Get the latest image and odometry message from the ROS network.
• Run the algorithm for detecting image features (ExampleHelperSignFollowingProcessImg)
function.
• Generate control commands from the Stateflow® chart using step.
• Publish the velocity control commands to the ROS network.
To visualize the masked image that the robot sees, change the value of doVisualization to true.
2-104
Sign Following Robot with ROS in MATLAB
ExampleHelperSignFollowingSetupPreferences;
doVisualization = false;
r = rosrate(10);
receive(imgSub);
receive(odomSub);
while(~controller.done)
% Get the latest sensor messages and process them.
imgMsg = imgSub.LatestMessage;
odomMsg = odomSub.LatestMessage;
[img,pose] = ExampleHelperSignFollowingROSProcessMsg(imgMsg, odomMsg);
% Log the subscribed image and odometry data into a bag file.
currentTime = rostime("now");
write(bagWriter,imgSub.TopicName,currentTime,imgMsg);
write(bagWriter,odomSub.TopicName,currentTime,odomMsg);
% Optionally visualize
% NOTE: Visualizing data will slow down the execution loop.
% If you have Computer Vision Toolbox, we recommend using
% vision.DeployableVideoPlayer instead of imshow.
if doVisualization
imshow(mask);
title(['Linear Vel: ' num2str(v) ' Angular Vel: ' num2str(w)]);
drawnow('limitrate');
end
% Pace the execution loop.
waitfor(r);
end
The robot follows the signs and stops at the final STOP sign. This figure shows the robot in motion.
2-105
2 ROS 2 Featured Examples
Delete the rosbagwriter object to close the bag file and reset the Gazebo scene after simulation
using the /gazebo/reset_simulation service. Create a rossvcclient object for the service. Use
the call object function to call the service and reset the Gazebo simulation scene.
delete(bagWriter);
gazeboResetClient = rossvcclient('/gazebo/reset_simulation',DataFormat = "struct");
call(gazeboResetClient);
Open the ROS Bag Viewer app by entering rosbagViewer in the MATLAB® Command Window. You
can also launch the app from the Apps section from the MATLAB toolstrip.
Click Open and load the generated sign_following_data.bag file. Inspect the Topic List and
Source Details panel on the left side of the app to check the bag file information. Launch Image and
Odometry visualizers from the toolstrip and select data sources. Use the Playback panel controls to
play the bag file and visualize the logged messages.
2-106
Sign Following Robot with ROS in MATLAB
After you verify the controller, you can generate a ROS node for the sign-following robot algorithm
using MATLAB Coder™ software. You can then deploy this node on the remote virtual machine
running Gazebo. Using deployment, you can run ROS nodes on remote machines directly, resulting in
faster executions. Create a MATLAB Coder configuration object that uses "Robot Operating System
(ROS)" hardware.
cfg = coder.config("exe");
cfg.Hardware = coder.hardware("Robot Operating System (ROS)");
Set configuration parameters. You can adjust these values so they are suitable for your remote device
and verify them before deployment. The robot follows the signs and stops at the final STOP sign.
Set the build action to "Build and Run" to ensure that the deployed ROS node starts running after
code generation.
Generate the ROS node and deploy the controller. The DeploySignFollowingRobotROS function
contains the controller algorithm code.
2-107
2 ROS 2 Featured Examples
Reset the Gazebo scene after the node executes by calling the rossvcclient object,
gazeboResetClient.
call(gazeboResetClient);
To rerun the deployed ROS node, create a rosdevice object. Specify the deviceAddress,
username, and password inputs to establish an SSH connection between the ROS device and
MATLAB.
gazeboVMDevice = rosdevice('192.168.192.129',"user","password");
Check the available nodes on the connected remote device. Verify that the deployed ROS node,
deploysignfollowingrobotros, exists on the remote device.
gazeboVMDevice.AvailableNodes
Run the ROS node on the remote device using runNode function. The robot follows the signs and
stops at the final STOP sign.
runNode(gazeboVMDevice,'deploysignfollowingrobotros')
2-108
Sign-Following Robot with ROS in Simulink
This example shows how to use Simulink® software to control a simulated robot running on a
separate ROS-based simulator. You can run this example using a Docker container or a virtual
machine.
In this example, you run a model that implements a sign-following algorithm and controls the
simulated robot to follow a path based on signs in the environment. The algorithm receives the
location information and camera information from the simulated robot, which is running in a separate
ROS-based simulator. The algorithm detects the color of the sign and sends the velocity commands to
turn the robot based on the color. In this example, the algorithm turns the robot to the left when it
encounters a blue sign and to the right when it encounters a green sign. The robot stops when it
encounters a red sign.
For an example that shows how to control a sign-following robot using ROS 2 or MATLAB®, see “Sign
Following Robot with ROS in MATLAB” on page 2-102. To run this example you can use Docker or
Virtual Machine.
This image is based on Ubuntu® Linux® and supports the sign-following robot examples in ROS
Toolbox.
Start a ROS-based simulator for a differential-drive robot and configure the Simulink® connection
with the robot simulator.
It creates a docker container and starts the Gazebo world in your Docker container.
You can use these options with the docker run command.
2-109
2 ROS 2 Featured Examples
• This image shows the command line output when you create a Docker container:
To view the Gazebo Sign Follower World, open any web browser and connect the the host port you
use to configure your Docker image. For this example, connect to localhost:8087.
2-110
Sign-Following Robot with ROS in Simulink
To get the IP address of the Docker container, execute this in a Terminal window.
This image shows the output of the docker inspect command when you pipe it to the grep
command.
Alternatively, you can run this example using a virtual machine (VM). You can download a VM image
that already has ROS and Gazebo software installed. This virtual machine is based on Ubuntu®
Linux® and supports the examples in ROS Toolbox.
2-111
2 ROS 2 Featured Examples
Setup the Simulink ROS preferences to communicate with the robot simulator.
open_system("signFollowingRobotROS.slx");
1 From the Prepare section of the Simulation tab, select ROS Network.
2 Specify the IP address and port number of the ROS master in Gazebo. For this example, the ROS
master in Gazebo is 192.168.0.1:11311. Enter 192.168.0.1 in the Hostname/IP address
box and 11311 in the Port Number box.
3 Click OK to apply changes and close the dialog.
At each time step, the algorithm detects a sign from the camera feed, decides which way to turn and
drives the robot. The Image Processing subsystem of the model detects the signs.
open_system("signFollowingRobotROS/Image Processing");
The Sign Tracking Logic subsystem implements a Stateflow® chart that takes in the detected
image size and coordinates from Image Processing subsystem and provides linear and angular
velocity to drive the robot.
Run Model
Run the model and observe the behavior of robot in the robot simulator.
• The video viewers show the actual camera feed and the detected sign image.
• In the simulator, the robot follows the sign and turns based on the color.
2-112
Sign-Following Robot with ROS in Simulink
• Simulation stops when the robot reaches the red sign at the end.
2-113
2 ROS 2 Featured Examples
This example shows how to use Simulink® to control a simulated robot running on a separate ROS-
based simulator. It then shows how to generate CUDA-optimized code for the ROS node, from the
Simulink model and deploy it to the localhost device.
In this example, you run a model that implements a sign-following algorithm and controls the
simulated robot to follow a path based on signs in the environment. The algorithm receives the
location information and camera information from the simulated robot, which is running in a separate
ROS-based simulator. The algorithm detects the color of the sign using a YOLO v2 detector and sends
the velocity commands to turn the robot based on the color. In this example, the algorithm is
designed to turn left when robot encounters a blue sign and turn right when robot encounters a
green sign. Finally the robot stops when it encounters a red sign.
To see this example using ROS 2 or MATLAB®, see “Sign Following Robot with ROS in MATLAB” on
page 2-102.
Start a ROS-based simulator for a differential-drive robot and configure the Simulink® connection
with the robot simulator.
This example uses a virtual machine (VM). For instructions on downloading the virtual machine, see
“Get Started with Gazebo and Simulated TurtleBot” on page 1-205.
exampleHelperGetYoloV2DirectionSignRecognitionNetwork()
Setup the Simulink ROS preferences to communicate with the robot simulator.
open_system('signFollowingRobotYOLOv2ROS.slx');
2-114
Sign Following Robot Using YOLOv2 Detection Algorithm with ROS in Simulink
On each time step, the algorithm detects a sign from the camera feed, decides on turn and drives it
forward. The sign detection is done using a pretrained YOLO v2 object detector in the Deep
Learning Object Detection subsystem of the model.
The Sign Tracking Logic subsystem implements a Stateflow® chart that takes in the detected
image size and coordinates from Deep Learning Object Detection and provides linear and angular
velocity to drive the robot.
set_param('signFollowingRobotYOLOv2ROS','GPUAcceleration','on');
set_param('signFollowingRobotYOLOv2ROS','SimDLTargetLibrary','cudnn');
set_param('signFollowingRobotYOLOv2ROS','DLTargetLibrary','cudnn');
Run the model and observe the behavior of the robot in the robot simulator.
• The video viewers show the actual camera feed and the detected sign image.
• In the simulator, the robot follows the sign and turns based on the color.
• The simulation stops automatically once the robot reaches the red sign at the end.
2-115
2 ROS 2 Featured Examples
Third-Party Prerequisities
2-116
Sign Following Robot Using YOLOv2 Detection Algorithm with ROS in Simulink
In Code Generation > Libraries > GPU Code pane, enable cuBLAS, cuSOLVER and cuFFT.
set_param('signFollowingRobotYOLOv2ROS','GPUcuBLAS','on');
set_param('signFollowingRobotYOLOv2ROS','GPUcuSOLVER','on');
set_param('signFollowingRobotYOLOv2ROS','GPUcuFFT','on');
To configure ROS node deployment on local host machine, in the Connect section of ROS tab, set
Deploy to to Localhost. Select the Build and Run button from ROS tab to deploy the node. At the
end of build process, you will see the ROS node running on local host machine.
2-117
2 ROS 2 Featured Examples
This example shows you how to use MATLAB® to control a simulated robot running on a separate
ROS-based simulator over ROS 2 network. It then shows how to generate a ROS 2 node for the
control algorithm and deploy it to a remote device. The example shown here uses ROS 2 and MATLAB
for simulation, and MATLAB Coder™ for code generation and deployment.
In this example, you run a MATLAB script that implements a sign-following algorithm and controls
the simulated robot to follow a path based on signs in the environment. The algorithm receives the
location information and camera information from the simulated robot, which is running in a separate
ROS-based simulator. The algorithm detects the color of the sign and sends the velocity commands to
turn the robot based on the color. In this example, the algorithm is designed to turn left when robot
encounters a blue sign and turn right when robot encounters a green sign. Finally the robot stops
when it encounters a red sign.
To see this example using ROS 1 or Simulink®, see “Sign Following Robot with ROS in MATLAB” on
page 2-102.
Start a ROS-based simulator for a differential-drive robot and configure the MATLAB® connection
with the robot simulator.
To follow along with this example, download a virtual machine using instructions in “Get Started with
Gazebo and Simulated TurtleBot” on page 1-205.
setenv('ROS_DOMAIN_ID','25')
ros2('topic','list')
/camera/camera_info
/camera/image_raw
/clock
/cmd_vel
/imu
/joint_states
/odom
/parameter_events
/rosout
/scan
/tf
domainID = 25;
n = ros2node("matlab_example_robot",domainID);
2-118
Sign Following Robot with ROS 2 in MATLAB
Create publishers and subscribers to relay messages to and from the robot simulator over the ROS 2
network. Update the Quality of Service (QoS) policies of publisher and subscriber. You need
subscribers for the image and odometry data. To control the robot, set up a publisher to send velocity
commands using the /cmd_vel topic.
Define the image processing color threshold parameters. Each row defines the threshold values for
the different colors.
This example provides an example helper MATLAB Stateflow® chart that takes in the image size,
coordinates from processed image, and the robot odometry poses. The chart provides linear and
angular velocity to drive the robot based on these inputs.
controller = ExampleHelperSignFollowingControllerChart;
open('ExampleHelperSignFollowingControllerChart');
2-119
2 ROS 2 Featured Examples
This section runs the controller to receive images and move the robot to follow the sign. The
controller does the following steps:
• Gets the latest image and odometry message from the ROS network.
• Runs the algoritm for detecting image features (ExampleHelperSignFollowingProcessImg).
• Generates control commands from the Stateflow® chart using step.
• Publishes the velocity control commands to the ROS network.
To visualize the masked image the robot sees, change the value of doVisualization variable to
true.
2-120
Sign Following Robot with ROS 2 in MATLAB
ExampleHelperSignFollowingSetupPreferences;
r = rateControl(10);
receive(imgSub); % Wait to receive an image message before starting the loop
receive(odomSub);
while(~controller.done)
% Get latest sensor messages and process them
imgMsg = imgSub.LatestMessage;
odomMsg = odomSub.LatestMessage;
[img,pose] = ExampleHelperSignFollowingProcessMsg(imgMsg, odomMsg);
% Optionally visualize
% NOTE: Visualizing data will slow down the execution loop.
% If you have Computer Vision Toolbox, we recommend using
% vision.DeployableVideoPlayer instead of imshow.
if doVisualization
imshow(mask);
title(['Linear Vel: ' num2str(v) ' Angular Vel: ' num2str(w)]);
drawnow('limitrate');
end
% Pace the execution loop.
waitfor(r);
end
You should see the robot moving in the ROS-based robot simulator as shown below.
2-121
2 ROS 2 Featured Examples
The robot follows the signs and stops at the final STOP sign. Reset the Gazebo scene after simulation
using the /reset_simulation service. Create a ros2svcclient object for the service and use the
call object function to call the service and reset the Gazebo simulation scene.
gazeboResetClient = ros2svcclient(n,'/reset_simulation','std_srvs/Empty');
call(gazeboResetClient);
After the controller is verified, the next step is to generate a ROS 2 node for the sign following robot
algorithm using MATLAB Coder™ and deploy it on the remote Virtual Machine running Gazebo.
Deployment enables ROS nodes to run on the remote machines directly, resulting in faster
executions. Create a MATLAB Coder configuration object that uses "Robot Operating System 2
(ROS 2)" hardware. For the Linux virtual machine for ROS Toolbox, set the following configuration
parameters before remote deployment. Note that the actual values might be different for your remote
device. Verify them before deployment. Set the build action to 'Build and Run' so that the deployed
ROS node starts running after code generation.
cfg = coder.config("exe");
cfg.Hardware = coder.hardware("Robot Operating System 2 (ROS 2)");
cfg.Hardware.DeployTo = 'Remote Device';
cfg.Hardware.RemoteDeviceAddress = '192.168.192.129';
cfg.Hardware.RemoteDeviceUsername = 'user';
cfg.Hardware.RemoteDevicePassword = 'password';
cfg.Hardware.BuildAction = "Build and run";
2-122
Sign Following Robot with ROS 2 in MATLAB
Use DeploySignFollowingRobotROS2 function that contains the controller algorithm code verified
in the previous section. Run the following command to generate the ROS node and deploy the
controller. You should see the robot moving in the Gazebo world.
---
Running ROS 2 node.
---
Use the 'ros2device' object to stop or start the generated node.
Code generation successful.
The robot follows the signs and stops at the final STOP sign. Reset the Gazebo scene after the node
executes by calling the rossvcclient object, gazeboResetClient.
call(gazeboResetClient);
To rerun the deployed ROS node from MATLAB, create a ros2device object specifying the
deviceAddress, username, and password values of the Virtual Machine running Gazebo. This
establishes an SSH connection between the ROS device and MATLAB. Check the available nodes on
the connected remote device. Verify that the deployed ROS node,
DeploySignFollowingRobotROS2, exists.
gazeboVMDevice = ros2device('192.168.192.129','user','password');
gazeboVMDevice.AvailableNodes
Run the ROS node deployed on the remote device using runNode function.
runNode(gazeboVMDevice,'DeploySignFollowingRobotROS2')
The node 'DeploySignFollowingRobotROS2' is already running on the ROS device. Use the 'stopNode'
2-123
2 ROS 2 Featured Examples
This example shows how to control a simulated robot running on a separate ROS-based simulator
over ROS 2 network using Simulink® software. You can run this example using a Docker container or
a virtual machine.
In this example, you run a model that implements a sign-following algorithm and controls the
simulated robot to follow a path based on signs in the environment. The algorithm receives the
location information and camera information from the simulated robot, which is running in a separate
ROS-based simulator. The algorithm detects the color of the sign and sends the velocity commands to
turn the robot based on the color. In this example, the algorithm turns the robot to the left when it
encounters a blue sign and to the right when it encounters a green sign. The robot stops when it
encounters a red sign.
For an example that shows how to control a sign-following robot using MATLAB®, see “Sign
Following Robot with ROS in MATLAB” on page 2-102.
This image is based on Ubuntu® Linux® and supports the sign-following robot examples in ROS
Toolbox.
Start a ROS-based simulator for a differential-drive robot and configure the Simulink® connection
with the robot simulator.
2-124
Sign-Following Robot with ROS 2 in Simulink
• This image shows the command line output when you create a Docker container:
To view the Gazebo Sign Follower World, open any web browser and connect the host port you use to
configure your Docker image. For this example, connect to localhost:8087.
2-125
2 ROS 2 Featured Examples
In the MATLAB Command Window, set the ROS_DOMAIN_ID environment variable to 25 to match the
robot simulator settings and run ros2 topic list to verify that the topics from the robot
simulator are visible in MATLAB.
setenv("ROS_DOMAIN_ID","25")
ros2("topic","list")
/camera/camera_info
/camera/image_raw
/clock
/cmd_vel
/imu
/joint_states
/odom
/parameter_events
/rosout
/scan
/tf
To get the IP address of the Docker container, execute this command in a Terminal window.
Alternatively, you can run this example using a virtual machine (VM). You can download a VM image
that already has ROS and Gazebo software installed. This virtual machine is based on Ubuntu®
Linux® and supports the examples in ROS Toolbox. To access the VM, follow these steps:
In the MATLAB Command Window, set the ROS_DOMAIN_ID environment variable to 25 to match the
robot simulator settings and run ros2 topic list to verify that the topics from the robot
simulator are visible in MATLAB.
setenv("ROS_DOMAIN_ID","25")
ros2("topic","list")
Setup the Simulink ROS preferences to communicate with the robot simulator.
2-126
Sign-Following Robot with ROS 2 in Simulink
open_system("signFollowingRobotROS2.slx");
1 From the Prepare section of the Simulation tab, select ROS Toolbox > ROS Network.
2 In Configure ROS Network Addresses, set the ROS 2 Domain ID value to 25.
3 Click OK to apply changes and close the dialog.
At each time step, the algorithm detects a sign from the camera feed, decides which way to turn and
drives the robot. The Image Processing subsystem of the model detects the signs.
open_system("signFollowingRobotROS2/Image Processing");
The Sign Tracking Logic subsystem implements a Stateflow® chart that takes in the detected
image size and coordinates from Image Processing and provides linear and angular velocity to
drive the robot.
Run Model
Run the model and observe the behavior of the robot in the robot simulator.
• The video viewers show the actual camera feed and the detected sign image.
• In the simulator, the robot follows the sign and turns based on the color.
• Simulation stops when the robot reaches the red sign at the end.
2-127
2 ROS 2 Featured Examples
2-128
Automated Parking Valet with ROS in MATLAB
This example shows how to distribute the “Automated Parking Valet” (Automated Driving Toolbox)
application among various nodes in a ROS network. Depending on your system, this example is
provided for ROS and ROS 2 networks using either MATLAB® or Simulink®. The example shown
here uses ROS and MATLAB. For the other examples, see:
Overview
This example is an extension of the “Automated Parking Valet” (Automated Driving Toolbox) example
in Automated Driving Toolbox™. A typical autonmous application has the following components.
For simplicity, this example concentrates on Planning, Control, and a simplified Vehicle Model. The
example uses prerecorded data to substitute localization information.
This application demonstrates a typical split of various functions into ROS nodes. The following
picture shows how the above example is split into various nodes. Each node: Planning, Control and
Vehicle is a ROS node implementing the functionalities shown as below. The interconnections
between the nodes show the topics used on each interconnection of the nodes.
2-129
2 ROS 2 Featured Examples
Setup
First, load a route plan and a given costmap used by the behavior planner and path analyzer.
Behavior Planner, Path Planner, Path Analyzer, Lateral and Lognitudinal Controllers are implemented
by helper classes, which are setup with this example helper function call.
exampleHelperROSValetSetupGlobals;
The initialized globals are organized as fields in the global structure, valet.
disp(valet)
2-130
Automated Parking Valet with ROS in MATLAB
rosinit;
masterHost = 'localhost';
The functions in the application are distributed amongst ROS nodes. This example uses three ROS
nodes: planningNode, controlNode, and vehicleNode.
Planning
The Planning node calculates each path segment based on the current vehicle position. This node is
responsible for generating the smooth path and publishes the path to the network.
• /smoothpath
2-131
2 ROS 2 Featured Examples
• /velprofile
• /directions
• /speed
• /nextgoal
• /currentvel
• /currentpose
• /desiredvel
• /reachgoal
Create publishers for planning node. Specify the message types for the publisher or subscriber for a
topic that is not present on ROS network.
2-132
Automated Parking Valet with ROS in MATLAB
planning.SpeedPub = ros.Publisher(planningNode,'/speed','std_msgs/Float64MultiArray');
planning.NxtPub = ros.Publisher(planningNode, '/nextgoal', 'geometry_msgs/Pose2D');
Create subscriber, GoalReachSub, to listen to the /reachgoal topic of planning node and specify
the callback action.
Control
The Control node is responsible for longitudinal and lateral controllers. This node publishes these
topics:
• /steeringangle
• /accelcmd
• /decelcmd
• /vehdir
• /reachgoal
• /smoothpath
• /directions
• /speed
• /currentpose
• /currentvel
• /nextgoal
• /velprofile
2-133
2 ROS 2 Featured Examples
Create the controller, controlNode, and setup the publishers and subscribers in the node.
% Create subscriber for /velprofile for control node and provide the callback function.
2-134
Automated Parking Valet with ROS in MATLAB
Vehicle
The Vehicle node is responsible for simulating the vehicle model. This node publishes these topics:
• /currentvel
• /currentpose
• /accelcmd
• /decelcmd
• /vehdir
• /steeringangle
On receiving a /steeringangle message, the vehicle simulator is run in the callback function,
exampleHelperROSValetVehicleCallback.
2-135
2 ROS 2 Featured Examples
2-136
Automated Parking Valet with ROS in MATLAB
Initialize Simulation
To initialize the simulation, send the first velocity message and current pose message. This message
causes the planner to start the planning loop.
curVelMsg = getROSMessage(vehicle.CurVelPub.MessageType);
curVelMsg.Data = valet.vehicleSim.getVehicleVelocity;
send(vehicle.CurVelPub, curVelMsg);
curPoseMsg = getROSMessage(vehicle.CurPosePub.MessageType);
curPoseMsg.X = valet.currentPose(1);
curPoseMsg.Y = valet.currentPose(2);
curPoseMsg.Theta = valet.currentPose(3);
send(vehicle.CurPosePub, curPoseMsg);
reachMsg = getROSMessage(control.VehGoalReachPub.MessageType);
reachMsg.Data = true;
send(control.VehGoalReachPub, reachMsg);
Main Loop
The main loop waits for the behavioralPlanner to say the vehicle reached the prepark position.
while ~reachedDestination(valet.behavioralPlanner)
pause(1);
end
2-137
2 ROS 2 Featured Examples
Park Maneuver
The parking maneuver callbacks are slightly different from the normal driving manueuver. Replace
the callbacks for the /velprofile and /reachgoal subscribers.
pause(1);
reachMsg = getROSMessage(control.VehGoalReachPub.MessageType);
reachMsg.Data = false;
send(control.VehGoalReachPub, reachMsg);
% Receive a message from the |/reachgoal| topic using the subcriber. This
% waits until a new message is received. Display the figure. The vehicle
% has completed the full automated valet manuever.
receive(GoalReachSub);
exampleHelperROSValetCloseFigures;
snapnow;
2-138
Automated Parking Valet with ROS in MATLAB
Delete the simulator and shutdown all the nodes by clearing publishers, subscribers and node
handles.
delete(valet.vehicleSim);
GoalReachSub.NewMessageFcn = [];
VelProfSub.NewMessageFcn = [];
2-139
2 ROS 2 Featured Examples
2-140
Automated Parking Valet with ROS in Simulink
Distribute an automated parking valet application among various nodes in a ROS network in
Simulink®. This example extends the “Automated Parking Valet” (Automated Driving Toolbox)
example in the Automated Driving Toolbox™. Using the Simulink model in the Automated Parking
Valet in Simulink example, tune the planner, controller and vehicle dynamics parameters before
partitioning the model into ROS nodes.
Prerequisite: “Automated Parking Valet” (Automated Driving Toolbox), “Generate a Standalone ROS
Node from Simulink” on page 1-194
Introduction
This example concentrates on simulating the Planning, Control and the Vehicle components. For
Localization, this example uses pre-recorded map localization data. The Planning component are
further divided into Behavior planner and Path Planner components. This results in a ROS network
comprised of four ROS nodes: Behavioral Planner, Path Planner, Controller and Vehicle
Sim. The following figure shows the relationships between each ROS node in the network and the
topics used in each.
2-141
2 ROS 2 Featured Examples
Observe the division of the components into four separate Simulink models. Each Simulink model
represents a ROS node.
2. The Vehicle model subsystem contains a Bicycle Model (Automated Driving Toolbox) block,
Vehicle Body 3DOF, to simulate the vehicle controller effects and sends the vehicle information.
2-142
Automated Parking Valet with ROS in Simulink
open_system('ROSValetBehavioralPlannerExample');
2. This model reads the current vehicle information, sends the next goal and checks if the vehicle has
reached the goal pose of the segment using exampleHelperROSValetGoalChecker.
3. The Behavior Planner and Goal Checker model runs when a new message is available on
either /currentpose or /currentvel.
4. The model sends the status if the vehicle has reached the parking goal using the /reachgoal
topic, which uses a std_msgs/Bool message. All the models stop simulation when this message is
true.
2-143
2 ROS 2 Featured Examples
open_system('ROSValetPathPlannerExample');
2. This model plans a feasible path through the environment map using a pathPlannerRRT
(Automated Driving Toolbox) object, which implements the optimal rapidly exploring random tree
(RRT*) algorithm and sends the plan to the controller over the ROS network.
3. The Path Planner subsystem runs when a new message is available on /plannerConfig or /
nextgoal topics.
2-144
Automated Parking Valet with ROS in Simulink
Controller Node
2. This model calculates and sends the steering and velocity commands.
3. The Controller subsystem runs when a new message is available on the /velprofile topic.
Model references in this example use “Implement Variations in Separate Hierarchy Using Variant
Subsystems” (Simulink) to achieve easy switch between simulation and code generation. During
simulation, messages pass from one node to other directly without ROS blocks to showcase the data
flow and execution order among these four ROS nodes. During code generation, variant subsystem
under each node will use publish and subscribe blocks to replace input and output ports. In this way,
after we lock down the control algorithm during simulation, each node can be deployed as a
standalone ROS node without any changes to the model.
Verify that the behavior of the model remains the same after partitioning the system into four
Simuilnk models.
1. Run rosinit in MATLAB® Command Window to initialize the global node and ROS master
rosinit
2-145
2 ROS 2 Featured Examples
2. Load the pre-recorded localization map data in MATLAB base workspace using the
exampleHelperROSValetLoadLocalizationData helper function.
exampleHelperROSValetLoadLocalizationData;
open_system('ROSValetSimulationExample.slx');
In the left parking selection area, you can also select a spot. The default parking spot is the sixth spot
at the top row.
sim('ROSValetSimulationExample.slx');
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 4 (Left:4)'
Warning: Inconsistent sample times. Sample time (0.1) of signal driving 'Input Port 1 (Left:1)' o
Warning: Inconsistent sample times. Sample time (0.1) of signal driving 'Input Port 2 (Left:2)' o
Warning: Inconsistent sample times. Sample time (0.1) of signal driving 'Input Port 3 (Left:3)' o
Warning: Inconsistent sample times. Sample time (0.1) of signal driving 'Input Port 8 (Top:1)' of
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 1 (Left:1)'
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 2 (Left:2)'
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 3 (Left:3)'
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 4 (Left:4)'
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 5 (Left:5)'
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 1' of 'ROSVa
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 2' of 'ROSVa
Warning: Inconsistent sample times. Sample time (0.05) of signal driving 'Input Port 3' of 'ROSVa
2-146
Automated Parking Valet with ROS in Simulink
Simulation Results
The Visualization subsystem in the vehicle model generates the results for this example.
open_system('ROSValetVehicleExample/Vehicle model/Visualization');
The visualizePath block is responsible for creating and updating the plot of the vehicle paths
shown previously. The vehicle speed and steering commands are displayed in a scope.
open_system("ROSValetVehicleExample/Vehicle model/Visualization/Commands")
2-147
2 ROS 2 Featured Examples
Generate ROS applications for Behavioral planner, Path planner, Controller nodes, and
simulate the Vehicle node in MATLAB and compare the results with simulation. For more
informaiton on generating ROS notes, see “Generate a Standalone ROS Node from Simulink” on page
1-194.
VEHICLE_MODE=1;
2. Deploy the Behavioral planner, Path planner and Controller ROS nodes.
open_system('ROSValetVehicleExample');
2-148
Automated Parking Valet with ROS in Simulink
5. Observe the vehicle movement on the plot and compare the results from simulation run.
rosshutdown
2-149
2 ROS 2 Featured Examples
This example shows how you can distribute “Automated Parking Valet” (Automated Driving Toolbox)
application among various nodes in a ROS 2 network.
Overview
This example is an extension of the “Automated Parking Valet” (Automated Driving Toolbox) example
in Automated Driving Toolbox™. A typical autonmous application has the following components.
For simplicity, this example concentrates on Planning, Control, and a simplified Vehicle Model. The
example uses prerecorded data to substitute localization information.
This application demonstrates a typical split of various functions into ROS nodes. The following
picture shows how the above example is split into various nodes. Each node: Planning, Control and
Vehicle is a ROS node implementing the functionalities shown as below. The interconnections
between the nodes show the topics used on each interconnection of the nodes.
2-150
Automated Parking Valet with ROS 2 in MATLAB
Setup
First, load a route plan and a given costmap used by the behavior planner and path analyzer.
Behavior Planner, Path Planner, Path Analyzer, Lateral and Lognitudinal Controllers are implemented
by helper classes, which are setup with this example helper function call.
exampleHelperROSValetSetupGlobals;
2-151
2 ROS 2 Featured Examples
Use nodes to split the functions in the application. This example uses three nodes: planningNode,
controlNode, and vehicleNode.
Planning
The Planning node calculates each path segment based on the current vehicle position. This node is
responsible for generating the smooth path and publishes the path to the network.
• /smoothpath
• /velprofile
• /directions
• /speed
• /nextgoal
• /currentvel
2-152
Automated Parking Valet with ROS 2 in MATLAB
• /currentpose
• /desiredvel
• /reachgoal
% Create publishers for planning node. Specify the message types the first
% time you create a publisher or subscriber for a topic.
planning.PathPub = ros2publisher(planningNode, '/smoothpath', 'std_msgs/Float64MultiArray');
planning.VelPub = ros2publisher(planningNode, '/velprofile', 'std_msgs/Float64MultiArray');
planning.DirPub = ros2publisher(planningNode, '/directions', 'std_msgs/Float64MultiArray');
planning.SpeedPub = ros2publisher(planningNode,'/speed','std_msgs/Float64MultiArray');
planning.NxtPub = ros2publisher(planningNode, '/nextgoal', 'geometry_msgs/Pose2D');
2-153
2 ROS 2 Featured Examples
Control
The Control node is responsible for longitudinal and lateral controllers. This node publishes these
topics:
• /steeringangle
• /accelcmd
• /decelcmd
• /vehdir
• /reachgoal
• /smoothpath
• /directions
• /speed
• /currentpose
• /currentvel
• /nextgoal
• /velprofile
2-154
Automated Parking Valet with ROS 2 in MATLAB
% Create subscribers for control node. Since all the message types for the
% topics are determined above, we can use the shorter version to create
% subscribers
control.PathSub = ros2subscriber(controlNode, '/smoothpath');
control.DirSub = ros2subscriber(controlNode, '/directions');
control.SpeedSub = ros2subscriber(controlNode, '/speed');
control.CurPoseSub = ros2subscriber(controlNode, '/currentpose');
2-155
2 ROS 2 Featured Examples
Vehicle
The Vehicle node is responsible for simulating the vehicle model. This node publishes these topics:
• /currentvel
• /currentpose
• /accelcmd
• /decelcmd
• /vehdir
• /steeringangle
2-156
Automated Parking Valet with ROS 2 in MATLAB
Initialize Simulation
To initialize the simulation, send the first velocity message and current pose message. This message
causes the planner to start the planning loop.
curVelMsg = ros2message(vehicle.CurVelPub);
curVelMsg.data = valet.vehicleSim.getVehicleVelocity;
send(vehicle.CurVelPub, curVelMsg);
curPoseMsg = ros2message(vehicle.CurPosePub);
curPoseMsg.x = valet.currentPose(1);
2-157
2 ROS 2 Featured Examples
curPoseMsg.y = valet.currentPose(2);
curPoseMsg.theta = valet.currentPose(3);
send(vehicle.CurPosePub, curPoseMsg);
reachMsg = ros2message(control.VehGoalReachPub);
reachMsg.data = true;
send(control.VehGoalReachPub, reachMsg);
Main Loop
The main loop waits for the behavioralPlanner to say the vehicle reached the prepark position.
while ~reachedDestination(valet.behavioralPlanner)
pause(1);
end
2-158
Automated Parking Valet with ROS 2 in MATLAB
Park Maneuver
The parking maneuver callbacks are slightly different from the normal driving manueuver. Replace
the callbacks for the /velprofile and /reachgoal subscribers.
reachMsg = ros2message(control.VehGoalReachPub);
reachMsg.data = false;
send(control.VehGoalReachPub, reachMsg);
% Receive a message from the |/reachgoal| topic using the subcriber. This
% waits until a new message is received. Display the figure. The vehicle
% has completed the full automated valet manuever.
receive(GoalReachSub);
exampleHelperROSValetCloseFigures;
snapnow;
2-159
2 ROS 2 Featured Examples
Delete the simulator and shutdown all the nodes by clearing publishers, subscribers and node
handles.
delete(valet.vehicleSim);
GoalReachSub.NewMessageFcn = [];
VelProfSub.NewMessageFcn = [];
2-160
Simulate Automated Parking Valet with ROS 2 in Simulink
This example shows how to distribute components of the Automated Parking Valet application into
various Simulink® models and simulate them in a known parking lot environment.
Observe the division of the components into four separate Simulink models. Each Simulink model
represents a ROS 2 node.
Vehicle Node
open_system('ROS2ValetVehicleExample');
2. The Vehicle model subsystem contains a Bicycle Model (Automated Driving Toolbox) block,
Vehicle Body 3DOF, to simulate the vehicle controller effects and sends the vehicle information.
2-161
2 ROS 2 Featured Examples
open_system('ROS2ValetBehavioralPlannerExample');
2. This model reads the current vehicle information, sends the next goal and checks if the vehicle has
reached the final pose of the segment using rosAutomatedValetHelperGoalChecker.
3. The Behavioral Planner and Goal Checker subsystem runs when a new message is available
on either /currentvel or /currentpose.
4. The model sends the status if the vehicle has reached the final parking goal using the /reachgoal
topic, which uses a std_msgs/Bool message type. All the models stop simulation when this message
is true.
2-162
Simulate Automated Parking Valet with ROS 2 in Simulink
open_system('ROS2ValetPathPlannerExample');
2. This model plans a feasible path through the environment map using a pathPlannerRRT
(Automated Driving Toolbox) object, which implements the optimal rapidly exploring random tree
(RRT*) algorithm and sends the plan to the controller.
3. The Path Planner subsystem runs when a new message is available on /plannerConfig or /
nextgoal topics.
2-163
2 ROS 2 Featured Examples
Controller Node
open_system('ROS2ValetControllerExample');
2. This model calculates and sends the steering and velocity commands.
3. The Controller subsystem runs when a new message is available on the /velprofile topic.
Model references in this example use “Implement Variations in Separate Hierarchy Using Variant
Subsystems” (Simulink) to achieve easy switch between simulation and code generation. During
simulation, messages pass from one node to other directly without ROS 2 blocks to showcase the data
flow and execution order among these four ROS 2 nodes. During code generation, variant subsystem
under each node will use publish and subscribe blocks to replace input and output ports. In this way,
after we lock down the control algorithm during simulation, each node can be deployed as a
standalone ROS 2 node without any changes to the model.
Verify that the behavior of the model remains the same after partitioning the system into four
Simulink models.
1. Load the pre-recorded localization map data in MATLAB base workspace using the
exampleHelperROSValetLoadLocalizationData helper function.
2-164
Simulate Automated Parking Valet with ROS 2 in Simulink
exampleHelperROSValetLoadLocalizationData;
open_system('ROS2ValetSimulationExample.slx');
In the left parking selection area, you can also select a spot. The default parking spot is the sixth spot
at the top row.
sim('ROS2ValetSimulationExample.slx');
Simulation Results
The Visualization subsystem in vehicle model generates the results for this example.
open_system('ROS2ValetVehicleExample/Vehicle model/Visualization');
The visualizePath block is responsible for creating and updating the plot of the vehicle paths
shown previously. The vehicle speed and steering commands are displayed in a scope.
open_system("ROS2ValetVehicleExample/Vehicle model/Visualization/Commands")
2-165
2 ROS 2 Featured Examples
2-166
Automated Parking Valet with ROS 2 in Simulink
Prerequisites: “Automated Parking Valet” (Automated Driving Toolbox), “Generate a Standalone ROS
2 Node from Simulink” on page 2-93
Introduction
This autonomous vehicle application has the following components.
This example concentrates on simulating the Planning, Control and the Vehicle components. For
Localization, this example uses pre-recorded localization map data. The Planning component is
further divided into Behavior planner and Path Planner components. This results in a ROS 2 network
comprised of four ROS 2 nodes: Behavioral Planner, Path Planner, Controller and
Vehicle. The following figure shows the relationships between each ROS 2 node in the network and
the topics used in each.
2-167
2 ROS 2 Featured Examples
The example follows this general workflow from algorithm design to deployment:
1 Design a Simulink model without enabling ROS and verify that the controller algorithm provides
accurate results
2 Replace the input and output ports with ROS 2 Subscribe and Publish blocks to prepare for
actual deployment
3 Generate and deploy ROS 2 nodes
This example walks you through the simulation and code generation workflow for the automated
parking valet components in these steps.
1 “Simulate Automated Parking Valet with ROS 2 in Simulink” on page 2-161 — Examine Simulink
models for all the components, and simulate the automated parking valet workflow.
2 “Generate and Deploy ROS 2 Nodes for Automated Parking Valet in Simulink” on page 2-169 —
Generate code and deploy the automated parking valet system components as ROS 2 nodes.
2-168
Generate and Deploy ROS 2 Nodes for Automated Parking Valet in Simulink
After simulating the ROS 2 nodes to verify all the components of the automated parking valet system
as described in “Simulate Automated Parking Valet with ROS 2 in Simulink” on page 2-161, you can
now generate code for those ROS 2 nodes and deploy them. Variant subsystem under each node will
use publish and subscribe blocks to replace input and output ports.
Generate and deploy Behavioral Planner, Path Planner and Controller node applications
using exampleHelperROS2ValetDeployNodes helper function. The helper function calls slbuild
(Simulink) command with the name of the Simulink model as input argument, for each model, to
generate C++ code and deploy the application on the host computer.
Recent change in GNU may result in a compilation error for ROS2ValetPathPlannerExample model. If
you encounter any compilation issues, follow these steps to update the model:
exampleHelperROSValetLoadLocalizationData;
exampleHelperROS2ValetDeployNodes(); % generate C++ code and deploy the application for ROS 2 nod
2-169
2 ROS 2 Featured Examples
Build Summary
Build Summary
2-170
Generate and Deploy ROS 2 Nodes for Automated Parking Valet in Simulink
Build Summary
2-171
2 ROS 2 Featured Examples
ROS 2 is based on the Data Distribution Service (DDS™) standard, an end-to-end middleware
protocol that provides features such as discovery, serialization, and transportation. ROS 2 supports
multiple ROS middleware (RMW) implementations so that you can choose one that best suits your
requirements. Use these factors to inform your choice of middleware implementation: platform
availability, performance characteristics, computation footprint, dependencies, and license.
You can switch between RMW implementations for using DDS while working with ROS 2 in
MATLAB® and Simulink®, by using ROS Toolbox Preferences. ROS Toolbox contains these RMW
implementations.
• rmw_fastrtps_cpp — eProsima Fast DDS (Version 2.6.4). This is the default RMW
implementation.
• rmw_fastrtps_dynamic_cpp — eProsima Fast DDS.
• rmw_cyclonedds_cpp — Eclipse Cyclone DDS (Version 0.9.1).
You can also configure and switch to these custom RMW implementations.
• rmw_connextdds — RTI Connext DDS (version 6.0.1 or later). This implementation is supported
on Windows®, Linux®, and macOS® operating systems.
• rmw_iceoryx_cpp — Eclipse Iceoryx Middleware (version 2.0.3). This implementation is
supported on Linux® and macOS® operating systems.
Additionally, you can switch to other custom RMW implementations based on dynamic or static
introspection type support in ROS 2 such as
1. In the Environment section of the Home tab in the MATLAB toolstrip, click Preferences and
select ROS Toolbox.
2-172
Switching Between ROS Middleware Implementations
2. Click Open ROS Toolbox Preferences, specify the path to the Python executable, and click
Recreate Python Environment. If you have configured Python already, proceed with the next step.
3. Open the dropdown list under ROS Middleware (RMW) Implementation to switch between
RMW implementations. Select an implementation from the list and click OK. This enables you to
create a ROS 2 node with the selected implementation.
2-173
2 ROS 2 Featured Examples
1. Open the ROS Toolbox Preferences window using the above steps and create the Python
environment.
2. Select Configure and Switch to Custom RMW Implementation in the dropdown list under
ROS Middleware (RMW) Implementation to launch the ROS Middleware Configuration dialog
box.
2-174
Switching Between ROS Middleware Implementations
2-175
2 ROS 2 Featured Examples
4. To set up rmw_connextdds, verify the underlying DDS installation (RTI Connext DDS). For more
information, see the links in the validation window.
2-176
Switching Between ROS Middleware Implementations
5. Click Browse and navigate to the parent directory of the DDS package. Build the RMW
implementation package and then click Next if the build is successful.
2-177
2 ROS 2 Featured Examples
6. Click Test RMW to validate if ROS 2 node creation is successful with the custom RMW
implementation set to rmw_connextdds.
2-178
Switching Between ROS Middleware Implementations
7. The selected ROS Middleware (RMW) Implementation is now registered as default in the
dropdown menu. Click OK to set this RMW implementation.
2-179
2 ROS 2 Featured Examples
1. Open the ROS Toolbox Preferences window using the above steps and create the Python
environment.
2. Select Configure and Switch to Custom RMW Implementation to launch the ROS
Middleware Configuration dialog box. Select other in the dropdown to provide the folderpath
containing one or multiple RMW implementations, based on dynamic or static introspection type
support. Click Next and proceed to validate their existence in the location.
2-180
Switching Between ROS Middleware Implementations
3. Providing the folderpath to a particular RMW implementation enables you to proceed with its
configuration.
2-181
2 ROS 2 Featured Examples
4. If the folder contains multiple RMW implementations, you can choose one or all from the dropdown
in the subsequent interface. Click Next upon making the selection.
2-182
Switching Between ROS Middleware Implementations
Note: Building RMW implementation based on static type support requires static ROS IDL type
support package. For example, rmw_ecal_proto_cpp requires rosidl_typesupport_protobuf,
which uses Protobuf for serialization and deserialization of ROS 2 messages.
2-183
2 ROS 2 Featured Examples
5. Provide the parent path to middleware installation and set the environment variables required to
build the RMW implementation package or packages.
2-184
Switching Between ROS Middleware Implementations
7. Additionally, build the ROS 2 message packages and custom messages to create ROS 2 node and
work with ROS 2 APIs or Simulink Blocks on the selected RMW implementation.
2-185
2 ROS 2 Featured Examples
8. Test it to validate the ROS 2 node creation with the RMW implementation set to
rmw_ecal_proto_cpp.
9. The selected ROS Middleware (RMW) Implementation is now registered as default in the
dropdown menu. Click OK to set this RMW implementation.
2-186
Switching Between ROS Middleware Implementations
Use these steps to configure RMW implementations based on other middleware as well, such as
openDDS, GurumDDS and further ones that are supported in ROS 2.
2-187
3
ROS Topics
3 ROS Topics
Introduction
Setting up a ROS network enables communication between different devices. These participants, or
nodes, all register with a ROS master to share information. Each ROS network has only one, unique
master. Each node is usually a separate device, although one device can have multiple nodes running.
MATLAB acts as one of these nodes when communicating on an existing ROS Network.
All devices must be connected to the same actual or virtual network for ROS connections to work. You
can create a new ROS master in MATLAB, or you can connect to an existing ROS master that is
running on a different device. If you connect to an external master, you have to know the IP address
or hostname of the device. The initial ROS master connection is created by calling rosinit. For
more information on setting up and using the ROS network, see “ROS Network Connection and
Exploration”.
Nodes communicate by sending messages using entities called publishers, subscribers, and services.
Publishers send data using topic names, which subscribers then receive over the network. Services
use clients to request information from a server. For more information on sending messages, see
“ROS Network Access in MATLAB”.
3-2
ROS Network Setup
Each node registers its own Node URI with the master. Other participants in the ROS network will
use this URI to contact the node. Again, this URI must be reachable by every other node in the ROS
network. To create a node in MATLAB, call rosinit. If a ROS master is already set up, MATLAB
detects it and sets the Node URI appropriately. Otherwise, it creates both a ROS master and node
that are connected.
By default, each MATLAB instance has a single global node. The node has a randomly generated
name assigned to it for uniqueness. All publishers, subscribers, service clients, and service servers
operate on this global node.
See Also
rosinit | rosnode | rostopic
Related Examples
• “Get Started with ROS” on page 1-40
• “Connect to a ROS Network” on page 1-45
• “Robot Operating System (ROS)”
3-3
3 ROS Topics
MATLAB supports a large library of ROS message types. This topic covers how MATLAB works with
ROS Messages by describing message structure, limitations for ROS messages, and supported ROS
data types. Refer to the full list of built-in message types at the end of this article.
For information about ROS 2 messages, see “Work with Basic ROS 2 Messages” on page 2-13.
ROS Messages
In MATLAB, ROS messages are stored as message structures or message objects. Message structures
are the recommended format as they have better performance over objects when performing initial
creation, reading them from rosbag files, accessing nested properties, and performing
communication operations over the ROS network. Also, message structures are the only supported
message format when generating code through MATLAB Coder™. For more information on the ROS
messages in MATLAB, see “Work with Basic ROS Messages” on page 1-53.
A ROS message structure is stored as a MATLAB structure data type with fields based on the
message type. Each message type has a specific set of fields with their corresponding values that are
individually stored and accessed. You can specifically point to and modify each field on its own. The
MessageType field of each message contains the message type as a character vector. Also, you can
use the rosShowDetails function to view the contents of the message.
pointMsg = rosmessage('geometry_msgs/Point','Dataformat','struct')
pointMsg =
MessageType: 'geometry_msgs/Point'
X: 0
Y: 0
Z: 0
You can access and modify each field by using the pointMsg structure.
pointMsg.Y = 2
pointMsg =
3-4
Built-In Message Support
MessageType: 'geometry_msgs/Point'
X: 0
Y: 2
Z: 0
For ROS message objects, all the rules of handle objects apply, including copying, modifying, and
other performance considerations. For more information on handle objects, see “Handle Object
Behavior”. Each handle points to the object for that specific message, which contains the information
relevant to that message type. The message type has a built-in structure for the data it contains.
ROS messages store the data relevant to that message type in a way similar to structure arrays. Each
message type has a specific set of properties with their corresponding values that are individually
stored and accessed. You can specifically point to and modify each property on its own. The
MessageType property of each message contains the message type as a character vector. Also, you
can use the showdetails function to view the contents of the message.
pointMsg = rosmessage('geometry_msgs/Point')
pointMsg =
MessageType: 'geometry_msgs/Point'
X: 0
Y: 0
Z: 0
You can access and modify each property by using the pointMsg handle.
pointMsg.Y = 2
pointMsg =
MessageType: 'geometry_msgs/Point'
X: 0
Y: 2
Z: 0
3-5
3 ROS Topics
Message properties can also have a variety of data types. MATLAB uses the rules set by ROS to
determine what these data types are. However, if they are to be used in calculations, you might have
to cast the data types to another value. The ROS data types do not convert directly to MATLAB data
types. For a detailed list of ROS data types and their MATLAB equivalent, see “ROS Data Type
Conversions” on page 3-6.
Supported Messages
Here is an alphabetized list of supported ROS packages. A package can contain message types,
service types, or action types.
To get a full list of supported message types, call rosmsg list in the MATLAB Command Window.
ROS Toolbox supports ROS Indigo and Hydro platforms, but your own ROS installation may have
different message versions. To overwrite our current message catalog, you can utilize the “Custom
Message Support” to generate new message definitions.
When specifying message types, input character vectors must match the character vector listed in
rosmsg list exactly. To use custom message types, MATLAB also provides a custom message
support package. For more information, see “ROS Custom Message Support” on page 3-27.
ackermann_msgs
actionlib
3-6
Built-In Message Support
actionlib_msgs
actionlib_tutorials
adhoc_communication
app_manager
applanix_msgs
ar_track_alvar
arbotix_msgs
ardrone_autonomy
asmach_tutorials
audio_common_msgs
axis_camera
base_local_planner
baxter_core_msgs
baxter_maintenance_msgs
bayesian_belief_networks
blob
bond
brics_actuator
bride_tutorials
bwi_planning
bwi_planning_common
calibration_msgs
capabilities
clearpath_base
cmvision
cob_base_drive_chain
cob_camera_sensors
cob_footprint_observer
cob_grasp_generation
cob_kinematics
cob_light
cob_lookat_action
cob_object_detection_msgs
cob_perception_msgs
cob_phidgets
cob_pick_place_action
cob_relayboard
cob_script_server
cob_sound
cob_srvs
cob_trajectory_controller
concert_msgs
control_msgs
control_toolbox
controller_manager_msgs
costmap_2d
create_node
data_vis_msgs
designator_integration_msgs
diagnostic_msgs
dna_extraction_msgs
driver_base
dynamic_reconfigure
dynamic_tf_publisher
dynamixel_controllers
dynamixel_msgs
epos_driver
ethercat_hardware
3-7
3 ROS Topics
ethercat_trigger_controllers
ethzasl_icp_mapper
explorer
face_detector
fingertip_pressure
frontier_exploration
gateway_msgs
gazebo_msgs
geographic_msgs
geometry_msgs
gps_common
graft
graph_msgs
grasp_stability_msgs
grasping_msgs
grizzly_msgs
handle_detector
hector_mapping
hector_nav_msgs
hector_uav_msgs
hector_worldmodel_msgs
household_objects_database_msgs
hrpsys_gazebo_msgs
humanoid_nav_msgs
iai_content_msgs
iai_kinematics_msgs
iai_pancake_perception_action
image_cb_detector
image_exposure_msgs
image_view2
industrial_msgs
interaction_cursor_msgs
interactive_marker_proxy
interval_intersection
jaco_msgs
joint_states_settler
jsk_footstep_controller
jsk_footstep_msgs
jsk_gui_msgs
jsk_hark_msgs
jsk_network_tools
jsk_pcl_ros
jsk_perception
jsk_rviz_plugins
jsk_topic_tools
keyboard
kingfisher_msgs
kobuki_msgs
kobuki_testsuite
laser_assembler
laser_cb_detector
leap_motion
linux_hardware
lizi
manipulation_msgs
map_merger
map_msgs
map_store
3-8
Built-In Message Support
mavros
microstrain_3dmgx2_imu
ml_classifiers
mln_robosherlock_msgs
mongodb_store
mongodb_store_msgs
monocam_settler
move_base_msgs
moveit_msgs
moveit_simple_grasps
multimaster_msgs_fkie
multisense_ros
nao_interaction_msgs
nao_msgs
nav_msgs
nav2d_msgs
nav2d_navigator
nav2d_operator
navfn
network_monitor_udp
nmea_msgs
nodelet
object_recognition_msgs
octomap_msgs
p2os_driver
pano_ros
pcl_msgs
pcl_ros
pddl_msgs
people_msgs
play_motion_msgs
polled_camera
posedetection_msgs
pr2_calibration_launch
pr2_common_action_msgs
pr2_controllers_msgs
pr2_gazebo_plugins
pr2_gripper_sensor_msgs
pr2_mechanism_controllers
pr2_mechanism_msgs
pr2_msgs
pr2_power_board
pr2_precise_trajectory
pr2_self_test_msgs
pr2_tilt_laser_interface
program_queue
ptu_control
qt_tutorials
r2_msgs
razer_hydra
rmp_msgs
robot_mechanism_controllers
robot_pose_ekf
roboteq_msgs
robotnik_msgs
rocon_app_manager_msgs
rocon_service_pair_msgs
rocon_std_msgs
3-9
3 ROS Topics
rosapi
rosauth
rosbridge_library
roscpp
roscpp_tutorials
roseus
rosgraph_msgs
rospy_message_converter
rospy_tutorials
rosruby_tutorials
rosserial_arduino
rosserial_msgs
rovio_shared
rtt_ros_msgs
s3000_laser
saphari_msgs
scanning_table_msgs
scheduler_msgs
schunk_sdh
segbot_gui
segbot_sensors
segbot_simulation_apps
segway_rmp
sensor_msgs
shape_msgs
shared_serial
sherlock_sim_msgs
simple_robot_control
smach_msgs
sound_play
speech_recognition_msgs
sr_edc_ethercat_drivers
sr_robot_msgs
sr_ronex_msgs
sr_utilities
statistics_msgs
std_msgs
std_srvs
stdr_msgs
stereo_msgs
stereo_wall_detection
tf
tf2_msgs
theora_image_transport
topic_proxy
topic_tools
trajectory_msgs
turtle_actionlib
turtlebot_actions
turtlebot_calibration
turtlebot_msgs
turtlesim
um6
underwater_sensor_msgs
universal_teleop
uuid_msgs
velodyne_msgs
view_controller_msgs
3-10
Built-In Message Support
visp_camera_calibration
visp_hand2eye_calibration
visp_tracker
visualization_msgs
wfov_camera_msgs
wge100_camera
wifi_ddwrt
wireless_msgs
yocs_msgs
zeroconf_msgs
See Also
rosmsg | rosmessage | showdetails
Related Examples
• “Work with Basic ROS Messages” on page 1-53
• “Exchange Data with ROS Publishers and Subscribers” on page 1-60
• “Work with Specialized ROS Messages” on page 1-94
3-11
3 ROS Topics
Transform laser scan data using a ROS transformation tree. When working with laser scan data, your
sensor might not be mounted in the center of the robot. Many localization algorithms make the
assumption that your sensor is mounted in the center of the robot. So depending on your robot
configuration, you must transform your laser scan data so it is relative to the robots center. This
example uses a ROS transformation tree to receive the transformations between different coordinate
frames. To transform the sensor data, you must be connected to a ROS network and have
transformations available.
Setup and connect to a ROS network. For this example, a sample network is already set up with an
existing transformation tree. You must specify the IP address of your ROS device, on which the
transformations are published.
rosinit('192.168.233.131')
Create the ROS transformation tree using rostf. The function connects to the ROS parameter server
for the network. Get the transform between the '/camera_link' and '/base_link' coordinate
frames. These coordinate frame names are dependent on your robot configuration.
tftree = rostf;
pause(1);
tf = getTransform(tftree,'/camera_link','/base_link',rostime('now'));
quat = [tf.Transform.Rotation.W,...
tf.Transform.Rotation.X,...
tf.Transform.Rotation.Y,...
tf.Transform.Rotation.Z];
rotm = quat2rotm(quat);
trvec = [tf.Transform.Translation.X,...
tf.Transform.Translation.Y ...
tf.Transform.Translation.Z];
tform = trvec2tform(trvec);
tform(1:3,1:3) = rotm(1:3,1:3);
Set up a subscriber to get laser scan data. Get the laser scan data as Cartesian points. Pad the points
with zeros for the z-axis and convert them to homogeneous coordinates.
scansub = rossubscriber('/scan');
scan = receive(scansub)
scan =
ROS LaserScan message with properties:
MessageType: 'sensor_msgs/LaserScan'
Header: [1×1 Header]
AngleMin: -0.5216
AngleMax: 0.5243
AngleIncrement: 0.0016
3-12
Transform Laser Scan Data From A ROS Network
TimeIncrement: 0
ScanTime: 0.0330
RangeMin: 0.4500
RangeMax: 10
Ranges: [640×1 single]
Intensities: [0×1 single]
cartScanData = scan.readCartesian;
cartScanData(:,3) = 0;
homScanData = cart2hom(cartScanData);
Ensure that there is something within scanning distance of your robot. If nothing is detected, a laser
scan will contain only NaN values, resulting in an error from cart2hom.
Apply the homogeneous transform and convert scan data back to Cartesian points.
trPts = tform*homScanData';
cartScanDataTransformed = hom2cart(trPts');
Get the polar angles and ranges from the Cartesian Points.
[angles,ranges] = cart2pol(cartScanDataTransformed(:,1),...
cartScanDataTransformed(:,2));
rosshutdown
3-13
3 ROS Topics
Introduction
A rosbag or bag is a file format in ROS for storing ROS message data. These bags are often created
by subscribing to one or more ROS topics, and storing the received message data in an efficient file
structure. MATLAB® can read these rosbag files and help with filtering and extracting message data.
The following sections detail the structure of rosbags in MATLAB and the workflow for extracting
data from them.
The BagSelection object has the following properties related to the rosbag:
ans =
Also, note that the BagSelection object contains an index for all the messages. However, you must
still use functions to extract the data. For extracting this information, see readMessages for getting
messages based on indices as a cell array or see timeseries for reading the data of specified
properties as a time series.
3-14
ROS Log Files (rosbags)
• Load a rosbag: Call rosbag and the file path to load file and create BagSelection.
• Examine available messages: Examine BagSelection properties (AvailableTopics,
NumMessages, StartTime, EndTime, and MessageList) to determine how to select a subset of
messages for analysis.
• Select messages: Call select to create a selection of messages based on your desired
properties.
• Extract message data: Call readMessages or timeseries to get message data as either a cell
array or time series data structure.
• Visualize, analyze or process data: Use the extracted data for your specific application. You can
plot data or develop algorithms to process data.
3-15
3 ROS Topics
3-16
ROS Log Files (rosbags)
Limitations
There are a few limitations in the rosbag support within MATLAB:
• MATLAB can only parse uncompressed rosbags. See the ROS Wiki for a tool to decompress a
compressed rosbag.
• Only rosbags in the v2.0 format are supported. See the ROS Wiki for more information on different
bag formats
• The file path to the rosbag must always be accessible. Because the message selection process
does not retrieve any data, the file needs to be available for reading when the message data is
accessed.
See Also
rosbag | readMessages | BagSelection
Related Examples
• “Work with rosbag Logfiles” on page 1-80
3-17
3 ROS Topics
This example shows how to work with complex ROS messages in MATLAB, such as messages with
nested submessages and variable-length arrays.
Some ROS message types have nested submessages that are of different message types. Such nested
ROS messages can be arrays whose length (number of elements) cannot be predetermined. Examples
of such message types include:
In this example, you send pose arrays of different lengths over a single topic that publishes messages
of type geometry_msgs/PoseArray. You then deploy the same as a ROS node.
Load the source data, which contains waypoints of different lengths that need to be published on a
single topic, for the robot to follow. The MAT file wayPointSets.mat loads two sets of waypoints.
These can be used to specify the pose array message. The waypoints are in the form of XYZ
coordinates.
load wayPointSets.mat;
Visualize the two sets of waypoints using the plot3 function. Note that the two sets contain different
numbers of waypoints.
figure
plot3(wayPointSet1(:,1),wayPointSet1(:,2),wayPointSet1(:,3),"*-")
grid on
xlabel("X")
ylabel("Y")
zlabel("Z")
title("Waypoint Set 1")
3-18
Publish Variable-Length Nested ROS Messages and Deploy as ROS Node Using MATLAB
figure
plot3(wayPointSet2(:,1),wayPointSet2(:,2),wayPointSet2(:,3),"*-r")
grid on
xlabel("X")
ylabel("Y")
zlabel("Z")
title("Waypoint Set 2")
3-19
3 ROS Topics
Use rosinit to create a ROS master in MATLAB and start a global node that is connected to the
master.
rosinit
Use rospublisher to create a ROS publisher for sending messages of type geometry_msgs/
PoseArray. Specify the name of the topic as /waypoints. Add a ROS subscriber that subscribes to
the published topic using rossubscriber. Use messages in struct format for better efficiency.
pub = rospublisher("/waypoints","geometry_msgs/PoseArray","DataFormat","struct");
sub = rossubscriber("/waypoints","DataFormat","struct");
Use rosmessage to create an empty message based on the topic published by the publisher, pub.
poseArrayMsg = rosmessage(pub);
3-20
Publish Variable-Length Nested ROS Messages and Deploy as ROS Node Using MATLAB
Specify the workspace variable corresponding to the waypoint set that you want to publish. Then,
populate the pose array with geometry_msgs/Pose messages. Assign the XYZ position fields of the
individual pose message elements from the waypoint set data. Continue adding new individual pose
message elements until the the pose array message contains all of the waypoint set data. Because
struct messages are not handles, the same structure can be reused when populating the array of
poses.
Use the send function to publish the pose array message to the topic /waypoints, using the ROS
publisher object, pub.
send(pub,poseArrayMsg);
pause(0.5)
View the pose array message data, as received by the subscriber, using the LatestMessage property
of the Subscriber object. Use horzcat to concatenate the position information extracted from the
received message into a structure array for the purposes of visualization. Use plot3 to visualize the
waypoints as received by the subscriber. Note that the visualization matches that of the
corresponding source waypoint data set.
receivedPoseArrayMsg1 = sub.LatestMessage;
waypointPositions1 = horzcat(receivedPoseArrayMsg1.Poses.Position);
figure
plot3([waypointPositions1.X],[waypointPositions1.Y],[waypointPositions1.Z],"*-")
grid on
xlabel("X")
ylabel("Y")
zlabel("Z")
title("Waypoint Set 1 Received Through ROS Topic")
3-21
3 ROS Topics
Now publish the second waypoint using the same procedure. Populate the pose array message with
the new set of waypoint information.
Use the send function to publish the new pose array message to the same topic via the same ROS
publisher object, pub.
send(pub,poseArrayMsg);
pause(0.5)
3-22
Publish Variable-Length Nested ROS Messages and Deploy as ROS Node Using MATLAB
Visualize the pose array message data received by the subscriber by following the same procedure as
before.
receivedPoseArrayMsg2 = sub.LatestMessage;
waypointPositions2 = vertcat(receivedPoseArrayMsg2.Poses.Position);
figure
plot3([waypointPositions2.X],[waypointPositions2.Y],[waypointPositions2.Z],"*-r")
grid on
xlabel("X")
ylabel("Y")
zlabel("Z")
title("Waypoint Set 2 Received Through ROS Topic")
The visualization matches that of the corresponding source waypoint data set, indicating the
successful broadcast of two sets of pose arrays with different lengths over a single topic.
3-23
3 ROS Topics
You can now generate a ROS node that uses the same workflow described in the previous section to
publish variable-length geometry_msgs/PoseArray messages. Then, you deploy the generated
node on the local machine.
Create a MATLAB Coder configuration object that uses "Robot Operating System (ROS)"
hardware. Set the build action to "Build and Run" and deploy to "Localhost" options so that the
deployed ROS node starts running on the local machine after code generation.
cfg = coder.config("exe");
cfg.Hardware = coder.hardware("Robot Operating System (ROS)");
cfg.Hardware.DeployTo = "Localhost";
cfg.Hardware.BuildAction = "Build and run";
Before ROS node generation, a necessary additional step is to initialize the variable-size data field in
the ROS message to an array of a maximum size. This step is necessary to prevent segmentation
faults as C++ requires preallocation of arrays. These lines of code perform the necessary steps.
% Create publisher
pub = rospublisher("/waypoints1","geometry_msgs/PoseArray","DataFormat","struct");
poseArrayMsg = rosmessage(pub);
% Specify maximum size of the pose array and initialize with empty pose messages
maxSize = 25;
poseArrayMsg.Poses = repmat(rosmessage('geometry_msgs/Pose',"DataFormat","struct"),maxSize,1);
Note that the variable-size field Poses is initialized to an array of 25 pose message structures. For
any other message types, you must initialize its corresponding variable-size data field in a similar
fashion.
---
Running ROS node.
Code generation successful.
Retrieve the latest message from the deployed node. Plot and visualize the received pose array
message. You notice that an additional waypoint pose at the origin is present in the received pose
array message. This is because the code initializes the position of unused pose elements to zero.
nodeSub = rossubscriber("/waypoints1","DataFormat","struct");
receivedPoseArrayMsg3 = receive(nodeSub,5);
waypointPositions3 = vertcat(receivedPoseArrayMsg3.Poses.Position);
figure
plot3([waypointPositions3.X],[waypointPositions3.Y],[waypointPositions3.Z],"*-r")
grid on
3-24
Publish Variable-Length Nested ROS Messages and Deploy as ROS Node Using MATLAB
xlabel("X")
ylabel("Y")
zlabel("Z")
title("Waypoint Set Received Through Deployed ROS Node")
Use rosshutdown to shut down the ROS network in MATLAB. Doing so, shuts down the ROS master
initialized by rosinit and deletes the global node.
rosshutdown
If the waypoint set data has orientation information, you can populate it in the quaternion orientation
fields of the individual pose message elements before publishing. To publish messages of type
nav_msgs/Path, use the same procedure, but specify the individual pose message elements as
geometry_msgs/PoseStamped type. To publish messages of any other type, specify the appropriate
nested message type as individual array elements, and ensure that the source data set contains the
required information you want to publish.
3-25
3 ROS Topics
See Also
3-26
ROS Custom Message Support
Custom message creation requires ROS packages, which are detailed in the ROS Wiki at Packages.
After ensuring that you have valid ROS packages for custom messages, call rosgenmsg with the file
path to the location containing the custom message package folders to generate the necessary
MATLAB code to use custom messages. For an example on how to generate a ROS custom message in
MATLAB, see “Create Custom Messages from ROS Package” on page 3-30.
If this is your first time using ROS custom messages, check “ROS Toolbox System Requirements”.
Note ROS Toolbox supports the existence of multiple custom messages folders on the MATLAB path
at any given time. These folders can contain multiple custom message packages.
The msg folder contains all your custom message type definitions. You should also add all custom
service type definitions to the srv folder and add all custom action type definitions to the action
folder. For example, the package custom_robot_msgs has this folder and file structure.
The package contains one custom message type in RobotTopic.msg and one custom service type in
RobotService.srv, and one custom action type in RobotAction.action. MATLAB uses these
3-27
3 ROS Topics
files to generate the necessary files for using the custom messages contained in the package. For
more information on creating msg and srv files, see Creating a ROS msg and srv and Defining
Custom Messages on the ROS Wiki. The syntax of these files is described on the pages specific to msg
and srv. For more information about ROS actions, see “ROS Actions Overview” on page 3-39.
Note You must have write access to the custom messages folder.
When ROS message definitions are converted to MATLAB, the field names are converted to
properties for the message object. Object properties always begin with a capital letter and do not
contain underscores. The field names are modified to fit this naming convention. The first letter and
the first letter after underscores are capitalized with underscores removed. For example, the
sensor_msgs/Image message has these fields in ROS:
header
height
width
encoding
is_bigendian
step
data
Header
Height
Width
Encoding
IsBigendian
Step
Data
This is also reflected when using ROS messages in Simulink. ROS message buses use the same
properties names as MATLAB.
The rosgenmsg function takes your custom message files (.msg, .srv, and .action) and converts
each message type to working MATLAB code. The rosgenmsg function looks for .msg files in the msg
folder, for .srv files in the srv folder, and for .action files in the action folder. This code is a
group of classes that define the message properties when you create new custom messages. The
function then creates the required MATLAB M-files for the different message classes.
After the rosgenmsg function creates these files, you must add the class files to the MATLAB path.
These steps are given as prompts in the MATLAB Command Window.
1 Add location of class files to MATLAB path: Use addpath to add new locations of files with
the .m extension to the MATLAB path and use savepath to save these changes.
3-28
ROS Custom Message Support
2 Refresh all message class definitions, which requires clearing the workspace:
clear classes
rehash toolboxcache
3 Verify messages are available: Use rosmsg list or the rosmessage function to check that
the new custom messages are available.
For an example of this procedure, see “Create Custom Messages from ROS Package” on page 3-30.
This example uses sample custom message files to create custom messages in MATLAB.
You need to complete this procedure only once for a specific set of custom messages. After that, you
can use the new custom messages like any other ROS message in MATLAB and take advantage of the
full ROS functionality that ROS Toolbox provides. Repeat this generation procedure when you would
like to update or create new message types.
You must maintain the MATLAB path that contain the files directories.
Custom message, service, and action types can be used with ROS Simulink blocks for generating C+
+ code for a standalone ROS node. The generated code (.tgz archive) will include Simulink
definitions for the custom messages, but it will not include the ROS custom message packages. When
the generated code is built in the destination Linux System, it expects the custom message packages
to be available in the catkin workspace or on the ROS_PACKAGE_PATH. Ensure that you either install
or copy the custom message package to your Linux system before building the generated code.
MATLAB provides a lot of built-in ROS message types. You can replace the definitions of those
message types with new definitions using the same custom message creation workflow detailed
above. When you are replacing the definitions of a built-in message package, you must ensure that
the custom message package folder contains new definitions (.msg files) for all the message types in
the corresponding built-in message package.
See Also
rosgenmsg | ros2genmsg
Related Examples
• “Create Custom Messages from ROS Package” on page 3-30
• “ROS 2 Custom Message Support” on page 4-2
• “ROS Toolbox System Requirements”
3-29
3 ROS Topics
To ensure you have the proper third-party software, see “ROS Toolbox System Requirements”.
After ensuring that your custom message package is correct, note the folder path location. Then, call
rosgenmsg with the specified path and follow the steps output in the command window. The
following example has three messages, A, B, and C, that have dependencies on each other. This
example also illustrates that you can use a folder containing multiple messages and generate them all
at the same time.
rehash toolboxcache
3 You can then use the custom messages like any other ROS messages supported in ROS Toolbox.
Verify these changes by either calling rosmsg list and search for your message types, or use
rosmessage to create a new message.
custommsg = rosmessage('B/Standalone')
custommsg =
3-30
Create Custom Messages from ROS Package
MessageType: 'B/Standalone'
IntProperty: 0
StringPropert: ''
This final verification shows that you have performed the custom message generation process
correctly. You can now send and receive these messages over a ROS network using MATLAB and
Simulink. The new custom messages can be used like normal message types. You should see them
create objects specific to their message type and be displayed in your workspace.
custommsg = rosmessage('B/Standalone');
custommsg2 = rosmessage('A/DependsOnB');
Custom messages can also be used with the ROS Simulink blocks.
See Also
rosgenmsg | ros2genmsg
3-31
3 ROS Topics
Related Examples
• “Generate ROS Custom Messages in MATLAB”
• “Create Custom Messages from ROS 2 Package”
• “ROS Toolbox System Requirements”
3-32
Generate ROS Custom Messages in MATLAB
Use custom messages to extend the set of message types currently supported in ROS. Custom
messages are messages that you define. If you are sending and receiving supported message types,
you do not need to use custom messages. To see the list of supported message types, enter rosmsg
list in the MATLAB® Command Window. For more information about supported ROS messages, see
“Work with Basic ROS Messages” on page 1-53.
If this is your first time working with ROS custom messages, see “ROS Toolbox System
Requirements”.
ROS custom messages are specified in ROS package folders that contain a folder named msg. The
msg folder contains all your custom message type definitions. For example, the simple_msgs
package in the rosCustomMessages folder, has this folder and file structure.
The package contains the custom message type Num.msg. MATLAB uses these files to generate the
necessary files for using the custom messages contained in the package.
In this example, you create ROS custom messages in MATLAB and compress them in a shareable ZIP
archive. You must have a ROS package that contains the required msg file.
After you prepare your custom message package folder, you specify the path to the parent folder and
call rosgenmsg with the specified path.
Open a new MATLAB session and create a custom message package folder in a local folder. Choose a
short folder path when you generate custom messages on a Windows machine to avoid limitations on
the number of characters in the folder path. For example,
genDir = fullfile('C:/test/rosCustomMessages')
genDir = fullfile(pwd,'rosCustomMessages');
packagePath = fullfile(genDir,'simple_msgs');
mkdir(packagePath)
Create a folder named msg inside the custom message package folder.
mkdir(packagePath,'msg')
3-33
3 ROS Topics
'Num.msg'),'w');
fprintf(fileID,'%s\n',messageDefinition{:});
fclose(fileID);
Create a folder named srv inside the custom message package folder.
mkdir(packagePath,'srv')
Create a folder named action inside the custom message package folder.
mkdir(packagePath,'action')
Generate custom messages from ROS definitions in .msg, .srv, and .action files. Use the
CreateShareableFile name-value argument to create a shareable ZIP archive of the generated
custom messages.
For information about how to use use this ZIP archive to register the custom messages in another
machine, see rosRegisterMessages.
rosgenmsg(genDir,CreateShareableFile=true)
3-34
Generate ROS Custom Messages in MATLAB
addpath('C:\test\rosCustomMessages\matlab_msg_gen_ros1\win64\install\m')
savepath
2. Refresh all message class definitions, which requires clearing the workspace, by executing:
clear classes
rehash toolboxcache
3-35
3 ROS Topics
In this example, you create ROS custom messages in MATLAB® to share them on another machine.
This other machine must run on the same platform and use the same version of MATLAB®. You must
have a ROS package that contains the required msg file, as this figure shows.
Open a new MATLAB session and create a custom message package folder in a local folder. Specify a
short folder path when you generate custom messages on a Windows machine to avoid limitations on
the number of characters in the folder path. For example,
genDir = fullfile('C:/Work/rosCustomMessages')
genDir = fullfile(pwd,'rosCustomMessages');
packagePath = fullfile(genDir,'simple_msgs');
mkdir(packagePath)
Create a folder named msg inside the custom message package folder.
mkdir(packagePath,'msg')
Create a folder named srv inside the custom message package folder.
mkdir(packagePath,'srv')
3-36
Register ROS Custom Messages to MATLAB
Create a folder named action inside the custom message package folder.
mkdir(packagePath,'action')
Generate the custom messages from the ROS definitions in .msg, .srv, and .action files as a
shareable ZIP archive.
rosgenmsg(genDir,CreateShareableFile=true)
addpath('C:\Work\rosCustomMessages\matlab_msg_gen_ros1\win64\install\m')
savepath
2. Refresh all message class definitions, which requires clearing the workspace, by executing:
clear classes
rehash toolboxcache
Copy the generated custom messages in the ZIP archive to the target computer and register it using
the rosRegisterMessages function.
rosRegisterMessages(genDir)
3-37
3 ROS Topics
addpath('C:\Work\rosCustomMessages\install\m')
savepath
2. Refresh all message class definitions, which requires clearing the workspace, by executing:
clear classes
rehash toolboxcache
Run rosmsg list on the target computer to view the custom messages for using in the workflow.
3-38
ROS Actions Overview
Use the sendGoal function to send goals to the server. Send the goal and wait for it to complete
using sendGoalAndWait. This function enables you to return the result message, final state of the
goal and status of the server. While the server is executing a goal, the callback function,
FeedbackFcn, is called to provide data relevant to that goal (see SimpleActionClient). Cancel
the current goal using cancelGoal or all goals on server using cancelAllGoals.
Use the sendFeedback function to send feedback messages to the client during goal execution.
During goal execution, the server calls the ExecuteGoalFcn callback. You can use
isPreemeptRequested within the callback function to check whether the client has cancelled the
goal or sent a new goal to execute.
3-39
3 ROS Topics
• To set up a ROS action server, use rosactionserver. Check what actions are available on a ROS
network by typing rosaction list in the MATLAB command window.
• Use rosactionclient to create action clients and connect them to the server. Specify an action
type currently available on the ROS network. Use waitForServer to wait for the action client to
connect to the server.
• Send a goal using sendGoal. Define a goalMsg that corresponds to the action type. When you
create an action client using rosactionclient, a blank goalMsg is returned. You can modify
this message with your desired parameters.
• When a goal status becomes 'active', the goal begins execution and the ActivationFcn
callback function is called. For more information on modifying this callback function, see
SimpleActionClient.
• While the goal status remains 'active', the server continues to execute the goal. The feedback
callback function processes information about this goals execution periodically whenever a new
feedback message is received. Use the FeedbackFcn to access or process the message data sent
from the ROS server.
3-40
ROS Actions Overview
• When the goal is achieved, the server returns a result message and status. Use the ResultFcn
callback to access or process the result message and status.
• GoalMsg — The goal message contains information about the goal. To perform an action, you
must send a goal message with updated goal information (see sendGoal). The type of goal
message depends on the type of ROS action.
• ActivationFcn — Once a goal is received on the action server, its status goes to 'pending'
until the server decides to execute it. The status is then 'active'. At this moment, MATLAB
executes the callback function defined in the ActivationFcn property of the
SimpleActionClient object. There is no ROS message or data associated with this function. By
default, this function simply displays 'Goal is active' on the MATLAB command line to notify
you the goal is being executed.
msg is the feedback message as an input argument to the function you define.
• ResultMsg — The server sends the final result message to the client after goal execution as the
output argument to sendGoal or sendGoalAndWait.
• ResultFcn — The result function executes when the goal has been completed. Inputs to this
function include both the result message and the status of execution. The type of result message
depends on the action type. This message, msg, and status, s, are the same as the outputs you get
when using sendGoalAndWait. This function can also be used to trigger dependent processes
after a goal is completed.
3-41
3 ROS Topics
See Also
rosactionserver | rosactionclient | rosaction
Related Examples
• “Move a Turtlebot Robot Using ROS Actions” on page 3-43
3-42
Move a Turtlebot Robot Using ROS Actions
This example shows how to use the /turtlebot_move action with a Turtlebot robot. The /
turtlebot_move action takes a location in the robot environment and attempts to move the robot to
that location.
Follow the steps in “Get Started with Gazebo and Simulated TurtleBot” on page 1-205 to setup a
simulated TurtleBot. After starting the virtual machine, launch Gazebo Empty world using desktop
shortcut and open the terminal window.
To run the Turtlebot ROS action server, use this command on the ROS distribution terminal.
~/start-turtlebot-move-action-server.sh
To connect to a ROS network, you must have an ROS action server setup on this network. For more
details on how to set ROS environment variables, see “Get Started with Gazebo and Simulated
TurtleBot” on page 1-205.
View the ROS actions available on the network. You must see /turtlebot_move available.
rosaction list
/turtlebot_move
3-43
3 ROS Topics
Create a simple action client to connect to the action server. Specify the action name. goalMsg is the
goal message for you to specify goal parameters. Use struct message format for better efficiency.
[client,goalMsg] = rosactionclient("/turtlebot_move","turtlebot_actions/TurtlebotMove","DataForma
waitForServer(client);
Set the parameters for the goal. The goalMsg contains properties for both the forward and turn
distances. Specify how far forward and what angle you would like the robot to turn. This example
moves the robot forward 2 meters.
goalMsg.ForwardDistance = single(2);
goalMsg.TurnDistance = single(0);
Set the feedback function to empty to have nothing output during the goal execution. Leave
FeedbackFcn as the default value to get a print out of the feedback information on the goal
execution.
client.FeedbackFcn = [];
Send the goal message to the server. Wait for it to execute and get the result message.
[resultMsg,~,~] = sendGoalAndWait(client,goalMsg)
rosshutdown
3-44
Execute Code Based on ROS Time
For other applications based on system time, consider the rateControl object.
This example shows to send regular commands to a robot at a fixed rate. It uses the Rate object to
execute a loop that publishes std_msgs/Twist messages to the network at a regular interval.
Setup ROS network. Specify the IP address if your ROS network already exists.
rosinit
[pub,msg] = rospublisher('/cmd_vel','geometry_msgs/Twist');
msg.Linear.X = 0.5;
msg.Angular.Z = -0.5;
desiredRate = 10;
rate = robotics.Rate(desiredRate);
rate.OverrunAction = 'drop'
rate =
rateControl with properties:
DesiredRate: 10
DesiredPeriod: 0.1000
OverrunAction: 'drop'
TotalElapsedTime: 0.0637
LastPeriod: NaN
Run loop and hold each iteration using waitfor(rate). Send the Twist message inside the loop.
Reset the Rate object before the loop to reset timing.
reset(rate)
3-45
3 ROS Topics
View statistics of fixed-rate execution. Look at AveragePeriod to verify the desired rate was
maintained.
statistics(rate)
rosshutdown
This example shows how to regularly publish and receive image messages using ROS and the
rosrate function. The rosrate function creates a Rate object to regularly access the /
camera/rgb/image_raw topic on the ROS network using a subscriber. The rgb image is converted
to a grayscale using rgb2gray and republished at a regular interval. Parameters such as the IP
address and topic names vary with your robot and setup.
sub = rossubscriber('/camera/rgb/image_raw');
pub = rospublisher('/camera/gray/image_gray','sensor_msgs/Image');
msgGray = rosmessage('sensor_msgs/Image');
msgGray.Encoding = 'mono8';
Receive the first image message. Extract image and convert to a grayscale image. Display grayscale
image and publish the message.
msgImg = receive(sub);
img = readImage(msgImg);
grayImg = rgb2gray(img);
imshow(grayImg)
3-46
Execute Code Based on ROS Time
writeImage(msgGray,grayImg)
send(pub,msgGray)
Create ROS Rate object to execute at 10 Hz. Set a loop time and the OverrunAction for handling
desiredRate = 10;
loopTime = 5;
overrunAction = 'slip';
rate = rosrate(desiredRate);
r.OverrunAction = overrunAction;
Begin loop to receive, process and send messages every 0.1 seconds (10 Hz). Reset the Rate object
before beginning.
reset(rate)
for i = 1:desiredRate*loopTime
msgImg = receive(sub);
img = readImage(msgImg);
grayImg = rgb2gray(img);
3-47
3 ROS Topics
writeImage(msgGray,grayImg)
send(pub,msgGray)
waitfor(rate);
end
View the statistics for the code execution. AveragePeriod and StandardDeviation show how well
the code maintained the desiredRate. OverRuns occur when data processing takes longer than the
desired period length.
statistics(rate)
rosshutdown
See Also
rateControl | rosrate | waitfor
3-48
Configure MATLAB Coder for ROS Node Generation
To generate C++ code for ROS Nodes from MATLAB functions, you must configure a MATLAB Coder
configuration object. This topic shows you how to configure the properties of the object to customize
ROS Node generation.
To create a MATLAB Coder configuration object, use the coder.config object. ROS Toolbox only
supports the executable build type for the MATLAB Coder configuration object.
cfg = coder.config('exe');
Then, you can specify these coder.Hardware properties specific to ROS node generation. For
remote device deployment, the device parameters automatically save to MATLAB preferences, and
are used the next time you set the deployment site to 'Remote Device'.
3-49
3 ROS Topics
3-50
Configure MATLAB Coder for ROS Node Generation
3-51
3 ROS Topics
For example, the following code specifies that the generated code must be deployed to the remote
device and run after build. It also specifies the remote device parameters.
For more information on ROS Node generation, see “MATLAB Programming for Code Generation” on
page 1-157.
To specify external ROS packages as dependencies for the generated ROS node, specify appropriate
custom toolchain options in the coder configuration object.
cfg.BuildConfiguration = 'Specify';
cfg.CustomToolchainOptions{4} = '"ROS_PKG1","ROS_PKG2"'; % Add ROS Required Packages
cfg.CustomToolchainOptions{6} = '/usr/include/opencv'; % Add Include Directories
cfg.CustomToolchainOptions{8} = '"-lopencv_core","-lopencv_shape"'; % Add Link Libraries
cfg.CustomToolchainOptions{10} = '/usr/lib/opencv'; % Add Library Paths
cfg.CustomToolchainOptions{12} = '-DMYVAR=1'; % Add Defines
3-52
Configure MATLAB Coder for ROS Node Generation
See Also
Related Examples
• “MATLAB Programming for Code Generation” on page 1-157
• “Generate a Standalone ROS Node” on page 1-163
3-53
3 ROS Topics
The ROS Bag Viewer app enables you to load a ROS or ROS 2 bag file into MATLAB and visualize all
the message content in the bag file. You can create separate viewers for different message types and
visualize them during playback. You can also control the playback of the bag file. You can also create
bookmarks during playback and switch between different bookmarks.
For more information on how to launch the app, see ROS Bag Viewer.
This example walks you through the ROS or ROS 2 bag file loading and playback workflow by using
two steps.
See Also
ROS Bag Viewer
3-54
Load and Play Bag File
You can open multiple instances of the app to play multiple ROS or ROS 2 bag files simultaneously.
• The Topic List shows the available topics in the ROS or ROS 2 bag file.
• The Source Details list the Name, Start time, End time, Duration and Message count of the
bag file.
3-55
3 ROS Topics
3-56
Load and Play Bag File
3-57
3 ROS Topics
3-58
Load and Play Bag File
3-59
3 ROS Topics
The ROS Bag Viewer app enables you to visualize messages in ROS and ROS 2 bag files. You can
create multiple viewers within the app and visualize different ROS and ROS 2 messages
simultaneously. For each viewer, you can filter the supported messages in the bag file and press the
You can choose to display the Elapsed Time or the Timestamp values associated with the bag file
along the slider tick labels. You can visualize the messages by putting a specific numeric value or
drag the slider to a particular value of the elapsed time or the time stamp. You can also take a
snapshot and export the information for further use.
1 Click Add in the Bookmark section of the app toolstrip. This opens the Add bookmark details
dialog.
3-60
Load and Play Bag File
2 Add the duration of the bookmark in seconds and specify a label. You can also tune the start time
of the bookmark.
Click OK. The app now adds a bookmark to the bag file starting from the start time for the
specified duration.
You can always view all the bookmarks that you have added as a table by clicking Manage in the
Bookmark section of the app toolstrip. Alternatively, you can also access the bookmark table by
clicking the Bookmarks tab at the top-right edge of the app canvas. From the bookmark table, you
can switch between different bookmarks, modify the bookmark parameters by double-clicking the
entries, or delete bookmarks.
• All visualizers
• Visualizer layout
• Bookmarks
3-61
3 ROS Topics
Reference Topic
Reference Topic is the topic whose frequency determines the bag file playback. The app displays all
the messages in the topic that you select as the main signal and displays other messages based on the
timestamps of the main signal. You can select a specific topic as the main signal using the Reference
Topic drop down. If you want to display all messages for all the topics specified among the
visualizers, select the topic with the highest frequency as the main signal. In this case, the app
repeats messages for the lower frequency topics among the visualizers while displaying all messages
from the highest frequency topic.
By default, the option for Reference Topic is Automatic. When you specify this option, based on the
visualizers present in the current instance, the app selects the main signal automatically using this
algorithm:
If you select the Automatic option, the app selects the lowest frequency topic as the main signal
when there are multiple visualizers of the same data type in the app instance. The app also has a
hierarchy preference for topics specified among image visualizers, followed by topics in point cloud,
laser scan, odometry visualizers. When the lowest frequency topic is selected as the main signal, the
app skips messages from other higher frequency topics specified among the visualizers while
displaying all the messages from the lowest frequency topic.
3-62
Control Bag File Playback
time in the numeric field next to the Elapsed Time Time drop down. You can enter a specific value of
elapsed time in this field and the app displays the latest messages corresponding to that time in all
the visualizers. Alternatively, you can drag the slider to visualize all messages at a specific time value.
If you select the Timestamp option from the drop down, the app displays the time stamp values
associated with the bag file along the slider tick labels. Timestamp is the current time of playing
messages from a particular topic in a rosbag file. It is represented in hh:mm:ss format on the
playback panel and displays the epoch convention in the numeric field. Similar to the Elapsed Time
option, you can seek through the bag file using the numeric field in the Timestamp window or the
slider. The visualizers update with the latest messages received at the selected timestamp.
Playback Options
After you play the bag file and start visualizing message data, you can change the playback direction
by clicking on the forward or backward button. If you wish to step through the messages in the bag
file instead, you must first pause the bag file playback and then use the forward or backward step
button. You can also set the speed in the Playback Speed drop-down for both message playback as
well as pause-and-step-through.
3-63
3 ROS Topics
This example shows how to use Simulink® to generate a ROS stepping enabled node and control a
simulated robot running on a separate ROS-based simulator.
In this example, you deploy a ROS node that implements a sign-following algorithm and controls the
simulated robot to follow a path based on signs in the environment. The algorithm receives the
location information and camera information from the simulated robot, which is running on a
separate ROS-based simulator. The algorithm detects the color of the sign and sends the velocity
commands to turn the robot based on the color. This example focuses on time source options for a
ROS node generated from Simulink.
To see this example using Simulink or ROS2, see “Sign-Following Robot with ROS in Simulink” on
page 2-109.
During Simulink simulation, you can control the simulation pace to iterate the model at a pace similar
to the robot running on the ROS device using one of these options:
1 Gazebo Pacer Block - If the robot is running on Gazebo, use a Gazebo Pacer block to achieve time
synchronization with Simulink. For an example, see “Sign Following Robot with Time
Synchronization Using ROS and Gazebo Co-Simulation” (Robotics System Toolbox).
2 Simulation Pacing Options (Simulink) - Use Simulation Pacing to change the simulation pace to
match with robot simulation time.
As for code generation and node deployment, the default time source is the system clock where the
deployed node is running. The generated node is expected to run at a rate that you specified in
Simulink. The rate may fluctuate based on the system specifications of the ROS device.
On the other hand, if there are more than one node in your project, you can use the time source
from /clock topic to achieve time synchronization. For instructions to enable ROS time model
stepping for deployment, see “Enable ROS Time Model Stepping for Deployed ROS Nodes” on page 6-
37.
If your simulator contains publisher to /clock topic, tune parameters and verify average rate for /
clock topic. For example, you can modify real time update rate and max step size in Gazebo
Open a ROS terminal, and run the following command to verify the average rate for /clock topic:
$ rostopic hz /clock
If the simulator does not publish a /clock topic, consider the following alternatives:
• Use a Digital Clock (Simulink) block as a time source in Simulink and run simulation to publish
to /clock topic.
• Use a Current Time block as a time source in Simulink and deploy node to publish to /clock
topic.
3-64
Deploy ROS Node for Sign Following Robot with Time Synchronization Using Simulink
You can use rosClockSimulator model to publish a /clock topic during simulation. You can adjust
the Sample time of Digital Clock block to change the publishing rate of /clock topic.
open_system('rosClockSimulator.slx');
In order to maintain the simulation rate you specified in simulink before deployment, /clock topic
must be updated consistently and at least twice faster than simulation rate. Otherwise, you may
experience warning or termination during run time.
This example shows you how to enable ROS time model stepping and generate node to control robot
for sign following.
Start a ROS-based simulator for a differential-drive robot and configure MATLAB® connection with
the robot simulator.
To follow along with this example, download a virtual machine using instructions in “Get Started with
Gazebo and Simulated TurtleBot” on page 1-205.
Setup the Simulink ROS preferences to communicate with the robto simulator.
On each time step, the algorithm detects a sign from the camera feed, decides on turn and drives it
forward. The sign detection is done in the Image Proecessing subsystem of the model.
open_system('signFollowingRobotROS/Image Processing');
The Sign Tracking Logic subsystem implements a Stateflow® chart that takes in the detected
image size and coordinates from Image Processing and provides linear and angular velocity to drive
the robot.
open_system('signFollowingRobotROS/Sign Tracking Logic');
In the Prepare section under ROS tab, click Hardware Settings to open the model configuration
parameters dialog box. Under Hardware Implementation > Hardware board settings > Target
3-65
3 ROS Topics
Hardware resources > ROS time, select Enable ROS time model stepping. Click OK to apply
changes and close the dialog.
(Optional) You can also select Enable notification after step check box if you wish to get a message
every time ROS time is published. See more information in “Enable ROS Time Model Stepping for
Deployed ROS Nodes” on page 6-37.
In the Connect section under ROS tab, make sure Deploy to is set to Remote Device. Click on Test
Connection to verify that Simulink is able to connect with the remove device. In the Deploy section
under ROS tab, click Build & Run to build, deploy, and start the program on remote device.
Once the deployed program starts running, the robot in the simulator will follow the sign and turn
based on the color.
3-66
Deploy ROS Node for Sign Following Robot with Time Synchronization Using Simulink
3-67
4
ROS 2 Topics
4 ROS 2 Topics
Custom message creation requires ROS 2 packages, which are detailed in the ROS Wiki at ROS 2
Packages. After ensuring that you have valid ROS 2 packages for custom messages, call ros2genmsg
with the file path to the location containing the custom message package folders to generate the
necessary MATLAB code to use custom messages. For an example on how to generate a ROS 2
custom message in MATLAB, see “Create Shareable ROS 2 Custom Message Package” on page 4-11.
If this is your first time using ROS 2 custom messages, check “ROS Toolbox System Requirements”.
Note ROS Toolbox supports the existence of multiple custom messages folders on the MATLAB path
at any given time. These folders can contain multiple custom message packages.
The msg folder contains all your custom message type definitions. You should also add all custom
service type definitions to the srv folder and add all custom action type definitions to the action
folder. For example, the package matlab_msg_gen has this folder and file structure.
The package contains one custom message type in Num.msg and one custom service type in
AddTwoInts.srv, and one custom action type in Test.action. MATLAB uses these files to
generate the necessary files for using the custom messages contained in the package. For more
information on creating msg and srv files, see Creating ROS 2 msg and srv on ROS 2 documentation.
4-2
ROS 2 Custom Message Support
The ros2genmsg function takes your custom message files (.msg, .srv, and .action) and converts
each message type to working MATLAB code. The ros2genmsg function looks for .msg files in the
msg folder, for .srv files in the srv folder, and for .action files in the action folder. This code is a
group of functions that define the message properties when you create new custom messages. The
function then creates the required MATLAB M-files for the different message functions.
After the ros2genmsg function creates these files, you must add the function files to the MATLAB
path. These steps are given as prompts in the MATLAB Command Window. Use ros2 msg list or
the ros2message function to verify that the new custom messages are available.
For an example of this procedure, see “Create Shareable ROS 2 Custom Message Package”. This
example uses sample custom message files to create custom messages in MATLAB.
You need to complete this procedure only once for a specific set of custom messages. After that, you
can use the new custom messages like any other ROS message in MATLAB and take advantage of the
full ROS functionality that ROS Toolbox provides. Repeat this generation procedure when you would
like to update or create new message types.
You must maintain the MATLAB path that contain the files directories.
Custom message, service, and action types can be used with ROS 2 Simulink blocks for generating C
++ code for a standalone ROS node. The generated code (.tgz archive) will include Simulink
definitions for the custom messages, but it will not include the ROS custom message packages. When
the generated code is built in the destination Linux System, it expects the custom message packages
to be available in the colcon workspace or on the ROS_PACKAGE_PATH with AMENT_PREFIX_PATH.
Ensure that you either install or copy the custom message package to your Linux system before
building the generated code.
MATLAB provides a lot of built-in ROS 2 message types. You can replace the definitions of those
message types with new definitions using the same custom message creation workflow detailed
above. When you are replacing the definitions of a built-in message package, you must ensure that
the custom message package folder contains new definitions (.msg files) for all the message types in
the corresponding built-in message package.
See Also
ros2genmsg | rosgenmsg
Related Examples
• “ROS Toolbox System Requirements”
• “Create Shareable ROS 2 Custom Message Package”
4-3
4 ROS 2 Topics
Use custom messages to extend the set of message types currently supported in ROS 2. Custom
messages are messages that you define. If you are sending and receiving supported message types,
you do not need to use custom messages. To see a list of supported message types, enter ros2 msg
list in the MATLAB® Command Window. For more information about supported ROS 2 messages,
see “Work with Basic ROS 2 Messages” on page 2-13.
If this if your first time working with ROS 2 custom messages, see “ROS Toolbox System
Requirements”.
ROS 2 custom messages are specified in ROS 2 package folders that contain a folder named msg. The
msg folder contains all your custom message type definitions. For example, the example_b_msgs
package in the custom folder, has this folder and file structure.
The package contains the custom message type Standalone.msg. MATLAB uses these files to
generate the necessary files for using the custom messages contained in the package.
In this example, you create ROS 2 custom messages in MATLAB. You must have a ROS 2 package that
contains the required msg file.
After ensuring that your custom message package is correct, you specify the path to the parent folder
and call ros2genmsg with the specified path. The following example provided three messages
example_package_a, example_package_b, and example_package_c that have dependencies.
This example also illustrates that you can use a folder containing multiple messages and generate
them all at the same time.
Open a new MATLAB session and create a custom message folder in a local folder.
folderPath = fullfile(pwd,"custom");
copyfile("example_*_msgs",folderPath);
Specify the folder path for custom message files and use ros2genmsg to create custom messages.
ros2genmsg(folderPath)
4-4
Create Custom Messages from ROS 2 Package
action_msgs/CancelGoalRequest
action_msgs/CancelGoalResponse
action_msgs/GoalInfo
action_msgs/GoalStatus
action_msgs/GoalStatusArray
actionlib_msgs/GoalID
actionlib_msgs/GoalStatus
actionlib_msgs/GoalStatusArray
builtin_interfaces/Duration
builtin_interfaces/Time
composition_interfaces/ListNodesRequest
composition_interfaces/ListNodesResponse
composition_interfaces/LoadNodeRequest
composition_interfaces/LoadNodeResponse
composition_interfaces/UnloadNodeRequest
composition_interfaces/UnloadNodeResponse
diagnostic_msgs/AddDiagnosticsRequest
diagnostic_msgs/AddDiagnosticsResponse
diagnostic_msgs/DiagnosticArray
diagnostic_msgs/DiagnosticStatus
diagnostic_msgs/KeyValue
diagnostic_msgs/SelfTestRequest
diagnostic_msgs/SelfTestResponse
example_a_msgs/DependsOnB
example_b_msgs/Standalone
example_c_msgs/DependsOnB
example_interfaces/AddTwoIntsRequest
example_interfaces/AddTwoIntsResponse
example_interfaces/Bool
example_interfaces/Byte
example_interfaces/ByteMultiArray
example_interfaces/Char
example_interfaces/Empty
example_interfaces/Float32
example_interfaces/Float32MultiArray
example_interfaces/Float64
example_interfaces/Float64MultiArray
example_interfaces/Int16
example_interfaces/Int16MultiArray
example_interfaces/Int32
example_interfaces/Int32MultiArray
example_interfaces/Int64
example_interfaces/Int64MultiArray
example_interfaces/Int8
example_interfaces/Int8MultiArray
example_interfaces/MultiArrayDimension
example_interfaces/MultiArrayLayout
example_interfaces/SetBoolRequest
example_interfaces/SetBoolResponse
example_interfaces/String
example_interfaces/TriggerRequest
4-5
4 ROS 2 Topics
example_interfaces/TriggerResponse
example_interfaces/UInt16
example_interfaces/UInt16MultiArray
example_interfaces/UInt32
example_interfaces/UInt32MultiArray
example_interfaces/UInt64
example_interfaces/UInt64MultiArray
example_interfaces/UInt8
example_interfaces/UInt8MultiArray
example_interfaces/WString
geometry_msgs/Accel
geometry_msgs/AccelStamped
geometry_msgs/AccelWithCovariance
geometry_msgs/AccelWithCovarianceStamped
geometry_msgs/Inertia
geometry_msgs/InertiaStamped
geometry_msgs/Point
geometry_msgs/Point32
geometry_msgs/PointStamped
geometry_msgs/Polygon
geometry_msgs/PolygonStamped
geometry_msgs/Pose
geometry_msgs/Pose2D
geometry_msgs/PoseArray
geometry_msgs/PoseStamped
geometry_msgs/PoseWithCovariance
geometry_msgs/PoseWithCovarianceStamped
geometry_msgs/Quaternion
geometry_msgs/QuaternionStamped
geometry_msgs/Transform
geometry_msgs/TransformStamped
geometry_msgs/Twist
geometry_msgs/TwistStamped
geometry_msgs/TwistWithCovariance
geometry_msgs/TwistWithCovarianceStamped
geometry_msgs/Vector3
geometry_msgs/Vector3Stamped
geometry_msgs/Wrench
geometry_msgs/WrenchStamped
lifecycle_msgs/ChangeStateRequest
lifecycle_msgs/ChangeStateResponse
lifecycle_msgs/GetAvailableStatesRequest
lifecycle_msgs/GetAvailableStatesResponse
lifecycle_msgs/GetAvailableTransitionsRequest
lifecycle_msgs/GetAvailableTransitionsResponse
lifecycle_msgs/GetStateRequest
lifecycle_msgs/GetStateResponse
lifecycle_msgs/State
lifecycle_msgs/Transition
lifecycle_msgs/TransitionDescription
lifecycle_msgs/TransitionEvent
logging_demo/ConfigLoggerRequest
logging_demo/ConfigLoggerResponse
map_msgs/GetMapROIRequest
map_msgs/GetMapROIResponse
map_msgs/GetPointMapROIRequest
map_msgs/GetPointMapROIResponse
map_msgs/GetPointMapRequest
4-6
Create Custom Messages from ROS 2 Package
map_msgs/GetPointMapResponse
map_msgs/OccupancyGridUpdate
map_msgs/PointCloud2Update
map_msgs/ProjectedMap
map_msgs/ProjectedMapInfo
map_msgs/ProjectedMapsInfoRequest
map_msgs/ProjectedMapsInfoResponse
map_msgs/SaveMapRequest
map_msgs/SaveMapResponse
map_msgs/SetMapProjectionsRequest
map_msgs/SetMapProjectionsResponse
nav_msgs/GetMapRequest
nav_msgs/GetMapResponse
nav_msgs/GetPlanRequest
nav_msgs/GetPlanResponse
nav_msgs/GridCells
nav_msgs/MapMetaData
nav_msgs/OccupancyGrid
nav_msgs/Odometry
nav_msgs/Path
nav_msgs/SetMapRequest
nav_msgs/SetMapResponse
pendulum_msgs/JointCommand
pendulum_msgs/JointState
pendulum_msgs/RttestResults
rcl_interfaces/DescribeParametersRequest
rcl_interfaces/DescribeParametersResponse
rcl_interfaces/FloatingPointRange
rcl_interfaces/GetParameterTypesRequest
rcl_interfaces/GetParameterTypesResponse
rcl_interfaces/GetParametersRequest
rcl_interfaces/GetParametersResponse
rcl_interfaces/IntegerRange
rcl_interfaces/ListParametersRequest
rcl_interfaces/ListParametersResponse
rcl_interfaces/ListParametersResult
rcl_interfaces/Log
rcl_interfaces/Parameter
rcl_interfaces/ParameterDescriptor
rcl_interfaces/ParameterEvent
rcl_interfaces/ParameterEventDescriptors
rcl_interfaces/ParameterType
rcl_interfaces/ParameterValue
rcl_interfaces/SetParametersAtomicallyRequest
rcl_interfaces/SetParametersAtomicallyResponse
rcl_interfaces/SetParametersRequest
rcl_interfaces/SetParametersResponse
rcl_interfaces/SetParametersResult
rosgraph_msgs/Clock
sensor_msgs/BatteryState
sensor_msgs/CameraInfo
sensor_msgs/ChannelFloat32
sensor_msgs/CompressedImage
sensor_msgs/FluidPressure
sensor_msgs/Illuminance
sensor_msgs/Image
sensor_msgs/Imu
sensor_msgs/JointState
4-7
4 ROS 2 Topics
sensor_msgs/Joy
sensor_msgs/JoyFeedback
sensor_msgs/JoyFeedbackArray
sensor_msgs/LaserEcho
sensor_msgs/LaserScan
sensor_msgs/MagneticField
sensor_msgs/MultiDOFJointState
sensor_msgs/MultiEchoLaserScan
sensor_msgs/NavSatFix
sensor_msgs/NavSatStatus
sensor_msgs/PointCloud
sensor_msgs/PointCloud2
sensor_msgs/PointField
sensor_msgs/Range
sensor_msgs/RegionOfInterest
sensor_msgs/RelativeHumidity
sensor_msgs/SetCameraInfoRequest
sensor_msgs/SetCameraInfoResponse
sensor_msgs/Temperature
sensor_msgs/TimeReference
shape_msgs/Mesh
shape_msgs/MeshTriangle
shape_msgs/Plane
shape_msgs/SolidPrimitive
simple_msgs/AddTwoIntsRequest
simple_msgs/AddTwoIntsResponse
simple_msgs/Num
statistics_msgs/MetricsMessage
statistics_msgs/StatisticDataPoint
statistics_msgs/StatisticDataType
std_msgs/Bool
std_msgs/Byte
std_msgs/ByteMultiArray
std_msgs/Char
std_msgs/ColorRGBA
std_msgs/Empty
std_msgs/Float32
std_msgs/Float32MultiArray
std_msgs/Float64
std_msgs/Float64MultiArray
std_msgs/Header
std_msgs/Int16
std_msgs/Int16MultiArray
std_msgs/Int32
std_msgs/Int32MultiArray
std_msgs/Int64
std_msgs/Int64MultiArray
std_msgs/Int8
std_msgs/Int8MultiArray
std_msgs/MultiArrayDimension
std_msgs/MultiArrayLayout
std_msgs/String
std_msgs/UInt16
std_msgs/UInt16MultiArray
std_msgs/UInt32
std_msgs/UInt32MultiArray
std_msgs/UInt64
std_msgs/UInt64MultiArray
4-8
Create Custom Messages from ROS 2 Package
std_msgs/UInt8
std_msgs/UInt8MultiArray
std_srvs/EmptyRequest
std_srvs/EmptyResponse
std_srvs/SetBoolRequest
std_srvs/SetBoolResponse
std_srvs/TriggerRequest
std_srvs/TriggerResponse
stereo_msgs/DisparityImage
test_msgs/Arrays
test_msgs/ArraysRequest
test_msgs/ArraysResponse
test_msgs/BasicTypes
test_msgs/BasicTypesRequest
test_msgs/BasicTypesResponse
test_msgs/BoundedSequences
test_msgs/Builtins
test_msgs/Constants
test_msgs/Defaults
test_msgs/Empty
test_msgs/EmptyRequest
test_msgs/EmptyResponse
test_msgs/MultiNested
test_msgs/Nested
test_msgs/Strings
test_msgs/UnboundedSequences
test_msgs/WStrings
trajectory_msgs/JointTrajectory
trajectory_msgs/JointTrajectoryPoint
trajectory_msgs/MultiDOFJointTrajectory
trajectory_msgs/MultiDOFJointTrajectoryPoint
unique_identifier_msgs/UUID
visualization_msgs/GetInteractiveMarkersRequest
visualization_msgs/GetInteractiveMarkersResponse
visualization_msgs/ImageMarker
visualization_msgs/InteractiveMarker
visualization_msgs/InteractiveMarkerControl
visualization_msgs/InteractiveMarkerFeedback
visualization_msgs/InteractiveMarkerInit
visualization_msgs/InteractiveMarkerPose
visualization_msgs/InteractiveMarkerUpdate
visualization_msgs/Marker
visualization_msgs/MarkerArray
visualization_msgs/MenuEntry
You can now use the above created custom message as the standard messages. For more information
on sending and receiving messages, see “Exchange Data with ROS 2 Publishers and Subscribers” on
page 2-19.
4-9
4 ROS 2 Topics
custom_msg = ros2message("example_b_msgs/Standalone");
custom_msg.int_property = uint32(12);
custom_msg.string_property='This is ROS 2 custom message example';
send(pub,custom_msg);
pause(3) % Allow a few seconds for the message to arrive
Use LatestMessage field to know the recent message received by the subscriber.
sub.LatestMessage
MATLAB provides a lot of built-in ROS 2 message types. You can replace the definitions of those
message types with new definitions using the same custom message creation workflow detailed
above. When you are replacing the definitions of a built-in message package, you must ensure that
the custom message package folder contains new definitions (.msg files) for all the message types in
the corresponding built-in message package.
4-10
Create Shareable ROS 2 Custom Message Package
In this example, you create a shareable ROS 2 custom message package in MATLAB. You must have a
ROS 2 package that contains the required msg file. This figure shows an example of an appropriate
folder structure.
After you prepare your custom message package folder, you specify the path to the parent folder and
call ros2genmsg with the specified path.
Open a new MATLAB session and create a custom message package folder in a local folder. Choose a
short folder path when you generate custom messages on a Windows machine to avoid limitations on
the number of characters in the folder path. For example,
genDir = fullfile('C:/test/ros2CustomMessages')
genDir = fullfile(pwd,'ros2CustomMessages');
packagePath = fullfile(genDir,'simple_msgs');
mkdir(packagePath)
Create a folder named msg inside the custom message package folder.
mkdir(packagePath,'msg')
Create a folder named srv inside the custom message package folder.
mkdir(packagePath,'srv')
4-11
4 ROS 2 Topics
'AddTwoInts.srv'),'w');
fprintf(fileID,'%s\n',serviceDefinition{:});
fclose(fileID);
Create a folder named action inside the custom message package folder.
mkdir(packagePath,'action')
Generate custom messages from ROS 2 definitions in .msg, .srv and .action files. Use the
CreateShareableFile name-value argument to create a shareable ZIP archive of the generated
custom messages.
For information about how to use use this ZIP archive to register the custom messages in another
machine, see ros2RegisterMessages.
ros2genmsg(genDir,CreateShareableFile=true);
Verify creation of the new custom messages by entering ros2 msg list in the Command Window.
4-12
Register ROS 2 Custom Messages to MATLAB
In this example, you create ROS 2 custom messages in MATLAB® to share them on another machine.
This other machine must run on the same platform and same version of MATLAB®. You must have a
ROS 2 package that contains the required msg file, as this figure shows.
Open a new MATLAB session and create a custom message package folder in a local folder. Specify a
short folder path when you generate custom messages on a Windows machine to avoid limitations on
the number of characters in the folder path. For example,
genDir = fullfile('C:/Work/ros2CustomMessages').
genDir = fullfile(pwd,'ros2CustomMessages');
packagePath = fullfile(genDir,'simple_msgs');
mkdir(packagePath)
Create a folder named msg inside the custom message package folder.
mkdir(packagePath,'msg')
Create a folder named srv inside the custom message package folder.
mkdir(packagePath,'srv')
4-13
4 ROS 2 Topics
Create a folder named action inside the custom message package folder.
mkdir(packagePath,'action')
Generate the custom messages from the ROS 2 definitions in .msg, .srv and .action files as a
shareable ZIP archive.
ros2genmsg(genDir,CreateShareableFile=true)
Copy the generated custom messages in the ZIP archive to the target computer and register it using
the ros2RegisterMessages function.
ros2RegisterMessages(genDir)
Run ros2 msg list on the target computer to view the custom messages for using in the workflow.
4-14
Register ROS 2 Custom Messages to MATLAB
4-15
4 ROS 2 Topics
To generate C++ code for ROS 2 Nodes from MATLAB functions, you must configure a MATLAB
Coder configuration object. This topic shows you how to configure the properties of the object to
customize ROS 2 Node generation.
By default the node uses the 'rmw_fastrtps_cpp' ROS middleware (RMW) implementation unless
otherwise specified by the RMW_IMPLEMENTATION environment variable. For more information on
RMW implementations see “Switching Between ROS Middleware Implementations” on page 2-172.
setenv('RMW_IMPLEMENTATION','rmw_cyclonedds_cpp')
Note
cfg = coder.config('exe');
Specify the Hardware property of the object as a 'Robot Operating System 2 (ROS 2)'
hardware configuration object, using the coder.hardware function.
Then, you can specify these coder.Hardware properties specific to ROS 2 node generation. For
remote device deployment, the device parameters automatically save to MATLAB preferences, and
are used the next time you set the deployment site to 'Remote Device'.
4-16
Configure MATLAB Coder for ROS 2 Node Generation
4-17
4 ROS 2 Topics
4-18
Configure MATLAB Coder for ROS 2 Node Generation
For example, the following code specifies that the generated code must be deployed to the remote
device and run after build. It also specifies the remote device parameters.
4-19
4 ROS 2 Topics
To specify external ROS packages as dependencies for the generated ROS node, specify appropriate
custom toolchain options in the coder configuration object.
cfg.BuildConfiguration = 'Specify';
cfg.CustomToolchainOptions{4} = '"ROS2_PKG1","ROS2_PKG2"'; % Add ROS 2 Required Packages
cfg.CustomToolchainOptions{6} = '/usr/include/opencv'; % Add Include Directories
cfg.CustomToolchainOptions{8} = '"-lopencv_core","-lopencv_shape"'; % Add Link Libraries
cfg.CustomToolchainOptions{10} = '/usr/lib/opencv'; % Add Library Paths
cfg.CustomToolchainOptions{12} = '-DMYVAR=1'; % Add Defines
See Also
ros2publisher | ros2subscriber | ros2node | ros2message
4-20
Generate a Standalone ROS 2 Node
This example shows how to generate C++ code for a standalone ROS 2 node from a MATLAB®
function. It then shows how to build and run the ROS 2 node on a Windows® machine.
Prerequisites
• An Ubuntu Linux system with ROS 2 and an SSH server installed. You can use your own Ubuntu
ROS 2 system, or you can use the Linux virtual machine for ROS Toolbox examples. For more
information, see “Get Started with Gazebo and Simulated TurtleBot” on page 1-205.
• A C/C++ compiler that is configured properly. You can use the mex -setup cpp to view and
change the default compiler. For more details, see Change Default Compiler.
Copy the robotROS2FeedbackControl function to your local directory and change the
defaultDesiredPos variable to the desired coordinates.
Start a Gazebo Empty World environment for ROS 2 from the Linux virtual machine by running these
running commands on the desktop. In the Linux virtual machine for ROS Toolbox, the turtlebot robot
is located at the [0,0] location by default. This Gazebo world contains a Turtlebot robot, which
publishes and subscribes to messages on a ROS 2 network.
~$ source /opt/ros/foxy/local_setup.bash
~$ export TURTLEBOT3_MODEL=burger && ros2 launch turtlebot3_gazebo empty_world.launch.py
Create a ros2device object. Specify the deviceAddress, username, and password values of the
Virtual Machine running Gazebo. This establishes an SSH connection between the ROS 2 device and
MATLAB.
gazeboVMDevice = ros2device('172.21.17.220',"user","password")
Create a MATLAB ROS 2 node in the same ROS network as the virtual machine. See the list of
available ROS 2 nodes.
Run the controller. The robot is moving towards the published destination. At the same time, observe
the trajectory of the robot. Keep this figure open to compare the behavior of MATLAB execution and
the generated executable node.
robotROS2FeedbackControl
To change the destination while the robot is moving. Open a new terminal in the virtual machine,
source the ROS repository, and publish the new destination coordinates in the form of a std_msgs/
Float64MultiArray message to the /dest topic.
4-21
4 ROS 2 Topics
~$ source /opt/ros/foxy/local_setup.bash
~$ ros2 topic pub -1 /dest std_msgs/Float64MultiArray "{data:[0,0]}"
You can also adjust the distanceThre, linearVelocity, and rotationGain values in the
robotROS2FeedbackControl.m to change the desired robot behavior. For the proportional
controller in this example, you must specify values in these ranges to ensure robust performance.
Alternatively, you can replace the proportional controller with a custom controller for performance
comparison. To view the behavior, reset the robot on the virtual machine by pressing Ctrl-R in
Gazebo.
distanceThre: 0<x<1
linearVelocity: 0<x<3
rotationGain: 0<x<6
The controller loop terminates after the robot reaches the goal or if more than 40 seconds has
elapsed since the start time. Alternatively, you can terminate the controller at any time using Ctrl-C
or entering this command in the terminal from the virtual machine. If you open a new terminal in the
virtual machine, you must source the ROS repository.
To generate a standalone C++ node, modify the function to make it compatible for code generation.
Reset the Gazebo scene after simulation using Ctrl-R on the virtual machine.
cfg = coder.config("exe");
cfg.Hardware = coder.hardware("Robot Operating System 2 (ROS 2)");
cfg.Hardware.BuildAction = "Build and run";
cfg.Hardware.RemoteDeviceAddress = '172.21.17.220';
cfg.Hardware.RemoteDeviceUsername = "user";
cfg.Hardware.RemoteDevicePassword = "password";
cfg.Hardware.DeployTo = "Remote Device";
codegen robotROS2FeedbackControlCodegen -args {} -config cfg
Reset the Gazebo scene by using Ctrl-R on the virtual machine and call
plotPathFeedbackControl to plot the robot trajectory.
plotPathFeedbackControl
4-22
Generate a Standalone ROS 2 Node
The configuration generates and runs the ROS 2 node on your remote device. You can opt to deploy
and run the ROS 2 node on the local machine by modifying the coder configuration object, cfg.
cfg = coder.config('exe');
cfg.Hardware = coder.hardware('Robot Operating System 2 (ROS 2)');
cfg.Hardware.BuildAction = 'Build and run';
cfg.Hardware.DeployTo = 'Localhost';
codegen robotROS2FeedbackControlCodegen -args {} -config cfg
plotPathFeedbackControl
After the generated executable starts running for the specified destination coordinates, you verify the
trajectory of the robot against the MATLAB execution. You can also observe the robot moving in
Gazebo on the virtual machine. You can publish a different destination coordinate while the robot is in
motion. The Control a ROS-Enabled Robot with a Function on page 4-21 section, which shows how to
publish a new set of destination coordinates through a virtual machine terminal.
Terminate the generated ROS 2 node by using the stopNode function of the ros2Device object.
Alternatively, you can terminate the execution by pressing Ctrl-C or sending a message to the /stop
topic. Reset the Gazebo scene by using Ctrl-R on VM Machine.
stopNode(gazeboVMDevice,'robotROS2FeedbackControlCodegen')
4-23
5
Configure MATLAB® Coder™ software to generate and build CUDA® ROS and CUDA® ROS 2 nodes
from a MATLAB function. You can deploy the CUDA nodes to local or remote GPU target devices.
In this example, you will deploy MobileNet-v2 object detection algorithm on a local host computer
with a supported NVIDIA graphics card.
Begin by creating a ROS publisher to publish the ROS image and run prediction on it using
MobileNet-v2 object detection algorithm. You then generate a local host node to deploy the object
detection algorithm on a local host computer with a CUDA-enabled NVIDIA GPU. Finally, you create a
ROS subscriber to plot the top five prediction scores.
Prerequisites
1. Install and set up these MathWorks® products and support packages: MATLAB® Coder™
(required), Embedded Coder® (recommended), GPU Coder™, and GPU Coder Interface for Deep
Learning (required for Deep Learning).
2. You can also install MATLAB® Coder™ Support Package for NVIDIA® Jetson™ and NVIDIA
DRIVE™ Platforms (required for an NVIDIA hardware connection).
3. Your target device can be a local host computer with a CUDA-enabled NVIDIA GPU, or a remote
device such as an NVIDIA Jetson board.
4. To use GPU Coder for CUDA code generation, you must install NVIDIA graphics driver, CUDA
toolkit, cuDNN library, and TensorRT library. For more information on local host deployment and host
simulation, see “Installing Prerequisite Products” (GPU Coder).
5. To set up the environment variables, see “Setting Up the Prerequisite Products” (GPU Coder).
6. To ensure you have the required third-party software, see “ROS Toolbox System Requirements”.
To verify that your development computer has the drivers, tools, libraries, and configuration required
for GPU code generation, see “Setting Up the Prerequisite Products” (GPU Coder).
Create a coder.gpuEnvConfig (GPU Coder) object and set its property values. Then, verify your
GPU code generation environment using the coder.checkGpuInstall (GPU Coder) function.
gpuEnvObj = coder.gpuEnvConfig;
gpuEnvObj.BasicCodegen = 1;
5-2
Generate CUDA ROS and CUDA ROS 2 Nodes Using MATLAB Coder and GPU Coder
gpuEnvObj.BasicCodeexec = 1;
gpuEnvObj.DeepLibTarget = "tensorrt";
gpuEnvObj.DeepCodeexec = 1;
gpuEnvObj.DeepCodegen = 1;
results = coder.checkGpuInstall(gpuEnvObj)
results =
gpu: 1
cuda: 1
cudnn: 1
tensorrt: 1
basiccodegen: 1
basiccodeexec: 1
deepcodegen: 1
deepcodeexec: 1
tensorrtdatatype: 1
profiling: 0
Write a MATLAB function to subscribe to the image and apply MobileNet-v2 algorithm to analyze the
probability of pepper.
type('mobilenet_ros1node_predictor.m')
function mobilenet_ros1node_predictor
% Copyright 2022 The MathWorks, Inc.
%#codegen
5-3
5 ROS and ROS 2 CUDA MATLAB Topics
imgSub = rossubscriber("/image_topic","sensor_msgs/Image","DataFormat","struct");
upperImageSize = [224,224,3];
in = zeros(upperImageSize,'uint8');
r = rosrate(30);
reset(r);
while (1)
receivedImage = imgSub.LatestMessage;
while ~isempty(receivedImage) && ~isempty(receivedImage.Data)
imageData = rosReadImage(receivedImage,"Encoding","rgb8");
% Crop the received image if it exceeds the upper size
imgSize = size(imageData);
index = min(imgSize,upperImageSize);
in(1:index(1),1:index(2),1:index(3)) = imageData(1:index(1),1:index(2),1:index(3));
scoresMsg.Data = zeros(1000,1,'single');
indexMsg.Data = zeros(1000,1,'single');
if ~isempty(scores)
scoresMsg.Data = single(scores');
indexMsg.Data = single(indexes');
end
send(scoresPub,scoresMsg);
send(indexPub,indexMsg);
end
waitfor(r);
end
end
Configure MATLAB Code Generation config object settings and generate local host node.
cfg = coder.config("exe");
Select Localhost to deploy the object detection algorithm on a local host computer with a CUDA-
enabled NVIDIA GPU.
5-4
Generate CUDA ROS and CUDA ROS 2 Nodes Using MATLAB Coder and GPU Coder
NOTE: Select Remote Hardware to deploy the object detection algorithm on a remote target device
such as NVIDIA Jetson board.
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 ty
cfg.GpuConfig = coder.GpuCodeConfig;
cfg.GpuConfig.Enabled = true;
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen mobilenet_ros1node_predictor -config cfg
Warning: Generation of C++ classes for MATLAB classes is not supported by GPU Coder. Disabling th
---
Running ROS node.
Warning: Function 'mobilenet_ros1node_predictor' does not terminate due to an infinite loop.
rosnode list
/matlab_global_node_73382
/mobilenet_ros1node_predictor
Create a publisher to read the ROS image and publish it to the /image_topic.
publishpepperimage
Subscribe to the topic and plot the top five prediction scores.
visualizepredictiondata
5-5
5 ROS and ROS 2 CUDA MATLAB Topics
To generate a CUDA ROS 2 node, follow the same steps that you used to generate a CUDA ROS node.
Replace all ROS functions with corresponding ROS 2 functions and configure the config object
settings for executable code.
cfg = coder.config("exe");
Select Localhost to deploy the object detection algorithm on a local host computer with a CUDA-
enabled NVIDIA GPU.
NOTE: Select Remote Hardware to deploy the object detection algorithm on a remote target device
such as NVIDIA Jetson board.
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 ty
cfg.GpuConfig = coder.GpuCodeConfig;
cfg.GpuConfig.Enabled = true;
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
Limitations
Related Topics
5-6
Generate CUDA ROS and CUDA ROS 2 Nodes Using MATLAB Coder and GPU Coder
5-7
6
In this section...
“ROS Model Reference” on page 6-2
“Remote Desktop” on page 6-2
“ROS 2 Model Build Failure” on page 6-2
The ROS Toolbox does not support the following ROS features in Simulink:
If your application requires these features, consider using MATLAB ROS functionality. You can write a
ROS node using MATLAB that can publish services, actions, and transformation trees to a topic as
ROS messages. Simulink can then subscribe to that topic to work with those messages. The following
functions are used in MATLAB to work with these features:
• Publish
• Subscribe
To see a full list of ROS support in Simulink, see “ROS Network Access in Simulink”.
• Multiple references to the same model results in an error due to duplicate buses with the same
name being created for ROS messages used by the ROS blocks. You can only reference a model
once in a parent model.
• Referenced data dictionaries are not supported with variable-size ROS messages.
• Simulation Mode only supports Normal mode.
Remote Desktop
Running ROS networks from remote desktop applications can cause ROS communication to be
interrupted. Consider executing your network without a remote connection.
6-2
ROS Simulink Support and Limitations
See Also
Related Examples
• “ROS Parameters in Simulink” on page 6-12
• “ROS Simulink Interaction” on page 6-4
• “Manage Array Sizes for ROS Messages in Simulink” on page 6-28
6-3
6 ROS Simulink Topics
When using Simulink to communicate with a ROS network or work with ROS functionality, there are
several points to note regarding its interaction with MATLAB and the ROS network.
By default, Simulink uses MATLAB ROS capabilities to resolve network information such as the
address of the ROS master. This network information can also be specified in Simulink using the
“Configure ROS Network Addresses” on page 6-21 dialog.
In simulation, the Simulink ROS node name is <modelName>_<random#>. This takes the model name
and adds a random number to the end to avoid node name conflicts.
In generated code, the node name is <modelName> (casing preserved). The model name is also used
in the archive used for generated code. Do not rename the tgz file from code generation (e.g.
ModelName.tgz). The file name is used to get the ROS package name and initiate the build.
In generated code, the model execution attempts to match actual elapsed time (the Fixed-step size
defines the actual time step, in seconds, that is used for the model update loop). However, this does
not guarantee real-time performance, as it is dependent on other processes running on the Linux®
system and the complexity of the model. If the deployed model is too slow to meet the execution
frequency, tasks are dropped. This drop is called an "overrun" and the model waits for the next
scheduled task. For more information, see the Tasking Mode section in the “Generate a Standalone
ROS Node from Simulink” on page 1-194 example.
6-4
ROS Simulink Interaction
You can also modify how your generated code runs for a deployed ROS node using rosdevice. The
rosdevice object allows you to connect to a ROS device, run nodes that are deployed, and modify
files on the device.
NOTE: If a custom topic name is specified for a Subscribe block, the topic is not required to exist
when the model is initialized. The Subscribe block will output blank messages until it receives a
message on the topic name you specify. This allows you to setup and test models before the rest of the
network has been setup.
6-5
6 ROS Simulink Topics
This model shows how to publish and subscribe to a ROS topic using Simulink®.
open_system('rosPubSubExample.slx')
Use the Blank Message and Bus Assignment blocks to specify the X and Y values of a
'geometry_msgs/Point' message type. Open the Blank Message block mask to specify the
message type. Open the Bus Assignment block mask to select the signals you want to assign. Remove
any values with '???' from the right column. Supply the Bus Assignment block with relevant values
for X and Y.
Feed the Bus output to the Publish block. Open the block mask and choose Specify your own as
the topic source. Specify the topic, '/location', and message type, 'geoemetry_msgs/Point'.
Add a Subscribe block and specify the topic and message type. Feed the output Msg to a Bus Selector
and specify the selected signals in the block mask. Display the X and Y values.
6-6
Publish and Subscribe to ROS Messages in Simulink
rosinit
Run the model. You should see the xPosition Out and yPosition Out displays show the
corresponding values published to the ROS network.
sim('rosPubSubExample')
rosshutdown
6-7
6 ROS Simulink Topics
This example illustrates how to update the header field of a ROS message using Simulink®.
Some ROS messages contain a specific Header field which maps to std_msgs/Header message type.
The Header field contains the timestamp and coordinate frame information of the ROS message. This
example model shows how to use the Header Assignment Block to update that information for a ROS
message, in Simulink®.
open_system('rosHeaderAssignmentBlockExampleModel.slx')
The Blank Message block creates an empty ROS message of type, sensor_msgs/LaserScan. Any
other message type that contains a Header field of type std_msgs/Header can be used here,
instead. The output of the Blank Message block is then fed to the Header Assignment block, which
updates the Header field of this message. For display, the frame_id and stamp values of the updated
ROS message Header are selected from the list of bus elements using Bus Selector blocks.
Additionally, a blank /rosgraph_msgs/Clock message is created and a custom time based on the
current simulation time is published to the /clock topic on the ROS network.
Open the Header Assignment block to display its block parameters. The Set Frame ID option is
selected and the name of the coordinate frame that is associated with the message is specified in the
text box as lidar_link. This will be set as the frame_id value for the Header. The Set Timestamp
option is also selected which sets the stamp value of the Header to the current ROS System time, by
default. The Header field name option is set to Use the default Header field name because,
the name of the Header field in a blank message is its default value, header. If you are using a ROS
message with a custom name for the Header field, you can select the Specify your own option
from the dropdown and specify the name of the Header field in the text box.
6-8
Update Header Field of a ROS Message in Simulink®
rosinit
Run the model. You can see the updated values for the frame_id and stamp fields of the ROS
Message in their respective displays.
sim('rosHeaderAssignmentBlockExampleModel')
In some cases it is useful to set the timestamp of a ROS message based on the time published by a
clock server than the ROS System time. A clock server is a specialized ROS node that publishes
timestamp to /clock topic in the form of rosgraph_msgs/Clock message type. In order to enable
this behavior for the Header Assignment block, set the /use_sim_time ROS parameter to true.
rosparam set /use_sim_time true
This configures the Header Assignment block to look for /clock topic on the ROS Network and
update the timestamp of the ROS Message accordingly. If /clock topic is not being published, the
timestamp will be zeros. Since the Header Assignment block updates during every sample hit, the
accuracy of the timestamp always depends on the step-size of the solver. Smaller step-size values
result in more accurate timestamp values. Run the model. You should see the time in stamp field of
the ROS message based on the published /clock topic, not the current ROS System Time.
sim('rosHeaderAssignmentBlockExampleModel')
6-9
6 ROS Simulink Topics
6-10
Time Stamp a ROS Message Using Current Time in Simulink
This example shows how to time stamp a ROS message with the current system time of your
computer. Use the Current Time block and assign the output to the std_msgs/Header message in
the Stamp field. Publish the message on a desired topic.
rosinit
Open the Simulink model provided with this example. The model uses a Bus Assignment block to
add the Current Time output to the Stamp field of the ROS message.
open_system('current_time_stamp_message.slx')
Run the model. The Publish block should publish the Header message with the current system time.
sim('current_time_stamp_message.slx')
rosshutdown
6-11
6 ROS Simulink Topics
These examples show how to get, set, compare, and manipulate ROS parameters in Simulink. To run
these examples, you must first set up a ROS network using rosinit. To set network-wide settings
and share values with the whole network, start a ROS parameter server using rosparam. Follow
these examples to see how to work with parameters in Simulink, including using string parameters.
This model gets and sets ROS parameters using Simulink®. This example illustrates how to use ROS
parameters in Simulink and to share data over the ROS network. An integer value is set as a
parameter on the ROS network. This integer is retrieved from the parameter server and compared to
a constant. The output Boolean from the comparison is also set on the network. Change the constant
block in the top left (blue) when you run the model to set network parameters based on user input
conditions.
You must be connected to a ROS network. Call rosinit in the MATLAB® command line.
6-12
ROS Parameters in Simulink
To create your string parameter, use a String Constant block and convert it to uint8 using a MATLAB
function block. The converted uint8 string is passed into the Set Parameter block along with the extra
input, Length, specified with a second Constant block. The Length refers to the maximum expected
string length and is required for all string parameters. For more information, see the Set Parameter
block.
6-13
6 ROS Simulink Topics
On ROS networks, strings parameters are stored as a uint8 array. When you get from string
parameters from the server, they are returned as a char array. In Simulink®, they are cast as uint8,
so you must use uint8 character vectors when comparing to the ROS string parameters. You can use
this comparison to trigger subsystems for larger models or validate settings for specific algorithms.
rosinit
ptree = rosparam;
Set a ROS parameter, /camera_format, to a string value. You can use string scalars or character
vectors. The value is stored as a uint8 array on the ROS parameter server and returned as 'jpeg'
in MATLAB®.
set(ptree,"/camera_format","jpeg")
pause(1)
pvalue = get(ptree,"/camera_format")
pvalue =
'jpeg'
Run the attached Simulink® model. This model checks to see if the previously set camera format
parameter is named 'jpeg'. To get the parameter off the server, use the Get Parameter block. Then,
compare the parameter to a character vector cast as uint8 from a Constant block, using a MATLAB
function block. An output of 1 means the parameters match.
open_system("rosStringParameterCompare")
sim("rosStringParameterCompare");
6-14
ROS Parameters in Simulink
This model shows how to access string parameters and use them to trigger subsystem operations. It
gets an image format off the set up ROS parameter server. It is retrieved as a uint8 array that is
compared using the strcmp MATLAB function block. When a new image is received from the
Subscribe block and the format is uint8('jpeg'), it triggers the "Process Image" block to perform
a task on the image data.
ptree = rosparam;
6-15
6 ROS Simulink Topics
Open the Simulink® model. This model checks the image format parameter and compares the value
to a uint8 cast character vector, uint8('jpeg') using a MATLAB® Function block. The boolean
output is fed to an AND operator with the IsNew output of a Subscribe block that gets the image off
the network. If the parameter value is correct and a new message is received, the Subsystem
"Process Image" is triggered.
Run the model and use the buttons in the model to change the image format parameter and verify the
strcmp function works. The eq output should be 1 when the parameter is set to 'jpeg'. While the
model is running, it is expected that image messages are being published on the network.
open_system("rosImageFormatParameter")
rosshutdown
eq = strcmp(string1, string2);
See Also
Get Parameter | Set Parameter
6-16
Play Back Data from Jackal rosbag Logfile in Simulink
Use the Read Data block to play back data from a rosbag logfile recorded from a Jackal™ robot from
ClearPath™ Robotics.
open_system('read_jackal_pose_log.slx')
Open the Read Data block mask to load a rosbag logfile. Click the Load logfile data link. Browse for
the logfile and specify a time offset or limited duration if needed. The jackal_sim.bag file is
attached to this example.
Run the model. The block plays back data in sync with the simulation time. The Record plot displays
the robot position over time.
sim(gcs)
6-17
6 ROS Simulink Topics
6-18
Call ROS Service in Simulink
Use the Call Service block to call a service on the ROS service server.
Set up a roscpp_tutorials/TwoInts service server message type and specify a example helper
callback function. The call back function provided sums the A and B elements of a
roscpp_tutorials/TwoIntsRequest message. The service server must be set up before you can
call a service client.
sumserver = rossvcserver('/sum','roscpp_tutorials/TwoInts',@exampleHelperROSSumCallback);
Open a Simulink® model with the Call Service block. Use the Blank Message block to output a
request message with the roscpp_tutorials/TwoIntsRequest message type. Populate the bus
with two values to sum together.
open_system('ros_twoint_service_simulink_example.slx')
Run the model. The service call should return 0 in the Resp output as part of the response message.
An error code of 0 indicates the service call was successful. You can ignore warnings about
converting data types.
sim('ros_twoint_service_simulink_example.slx')
Warning: The property "A" in ROS message type "roscpp_tutorials/TwoIntsRequest" with data type (i
Suggested Actions:
• Remove conversion of ROS message properties with "int64" data type to "double" in the Simul
Warning: The property "B" in ROS message type "roscpp_tutorials/TwoIntsRequest" with data type (i
Suggested Actions:
• Remove conversion of ROS message properties with "int64" data type to "double" in the Simul
6-19
6 ROS Simulink Topics
Warning: The property "Sum" in ROS message type "roscpp_tutorials/TwoIntsResponse" with data type
Suggested Actions:
• Remove conversion of ROS message properties with "int64" data type to "double" in the Simul
rosshutdown
6-20
Configure ROS Network Addresses
For the ROS master URI, if Network Address is set to Default, Simulink uses the following rules to
set the ROS Master URI:
6-21
6 ROS Simulink Topics
For the Node Host, if Network Address is set to Default, Simulink uses the following rules to set
the ROS Node Host:
For both, these are the same rules that MATLAB uses to resolve its ROS network addresses.
Otherwise, if you chose Custom, you can set all the variables as shown below. This overrides the
environment variables.
Note: These addresses are saved in MATLAB preferences, not the model. Therefore, this information
is shared across all Simulink models and multiple MATLAB installs of the same release.
6-22
Configure ROS Network Addresses
You can also use the Test button to ensure you can connect to the ROS master. If you get an error,
call rosinit to setup a local ROS network, or if you specified a remote ROS master, check your
settings are correct.
The custom ROS master or node host settings are not used in generated code when deploying a
standalone node.
See Also
rosinit
Related Examples
• “Get Started with ROS” on page 1-40
6-23
6 ROS Simulink Topics
More About
• “ROS Simulink Interaction” on page 6-4
• “Select ROS Topics, Messages, and Parameters” on page 6-25
• “ROS Simulink Support and Limitations” on page 6-2
6-24
Select ROS Topics, Messages, and Parameters
In this section...
“Select ROS Topics” on page 6-25
“Select ROS Message Types” on page 6-26
“Select ROS Parameter Names” on page 6-26
This dialog shows the list of topics available on the ROS master. Selecting a topic from the list
automatically populates the Topic and Message type parameters for the corresponding block mask
dialog. If the message type is not supported in MATLAB ROS, Simulink will throw an error. Once the
topic is selected, it is saved with the block. Even if the topic is not longer available on the network,
the block will still use that topic name.
To use a topic not currently posted on the ROS network or if you are not currently connected, use the
“Specify your own” option under the Topic Source parameter in your block mask dialog.
6-25
6 ROS Simulink Topics
This is the list of all message types supported in MATLAB ROS including any custom message types.
You can begin typing in the name of your desired message type or manually search through the list.
The selected message type is stored with the block and saved with the model.
Note: When using code generation, message type information is not included. You must ensure that
your Linux ROS environment has the ROS packages installed that contain the necessary message
type definitions.
6-26
Select ROS Topics, Messages, and Parameters
This is the list of parameters you can select from the ROS parameter server. The parameters that are
grayed out have unsupported data types. Select a parameter name that is not grayed out and click
OK. This should auto-fill the Name and Data type into the block parameters.
See Also
Blank Message | Get Parameter | Publish | Set Parameter | Subscribe
Related Examples
• “ROS Parameters in Simulink” on page 6-12
• “Manage Array Sizes for ROS Messages in Simulink” on page 6-28
6-27
6 ROS Simulink Topics
If you are working with variable-length signals in Simulink, the nonvirtual bus used for messages
cannot contain variable-length arrays as properties. All variable-length arrays are converted to fixed-
length arrays for nonvirtual buses. Therefore, you must manage the maximum size for these fixed-size
arrays.
Ensure that your Simulink model is configured for ROS. If it not, follow these steps:
1 On the Apps tab, under Control Systems, click Robot Operating System (ROS).
2 In the Robot Operating System (ROS) dialog box that opens up, select Robot Operating
System (ROS) from the ROS Network drop-down. This opens up the ROS tab in the toolstrip
which shows the specified ROS Network in the Connect section.
Then, in the Simulation tab, select ROS Toolbox > Variable Size Message to manage array sizes.
If your model uses ROS messages with variable-length arrays, the following dialog box opens.
Otherwise, Simulink displays a message.
Because the message properties have a variable length, it is possible that they can be truncated if
they exceed the maximum size set for that array. You have the option of Truncate with warning
or Truncate silently. Either way, the simulation will run, but Truncate with warning displays
a warning in the Diagnostic Viewer that the message property has been truncated. When using
6-28
Manage Array Sizes for ROS Messages in Simulink
generated code, the warning will be emitted using Log Statements in ROS. The warning will be a
ROS_WARN_NAMED log statement and the name is the model name.
The Message types in model section shows all the ROS message types that are currently used by
Publish, Subscribe and Blank Message blocks in your Simulink model. You have the option to use the
default limits for this message type by clicking the check box. Otherwise, select each message type
individually to set the Maximum length (items) of each Array Property as desired. This maximum
length is applied to all instances of that message type for that model. The maximum length is also
stored with the model. Therefore, it is possible to have two models accessing the same message type
with different maximum length limits.
Managing the size of your variable-length arrays can help improve performance. If you limit the size
of the array to only include relevant data, you can process data more effectively. However, when
running these models, consider possible issues associated with truncation and what could happen to
your system if some data is ignored.
Note: If you would like to know the appropriate maximum lengths for different message types. You
can simulate the model and observe the sizes output in the warning. To see an example of using ROS
messages and working with variable-length arrays, see “Get Started with ROS in Simulink” on page
1-127.
See Also
Publish | Subscribe
Related Examples
• “Get Started with ROS in Simulink” on page 1-127
• “ROS Simulink Support and Limitations” on page 6-2
6-29
6 ROS Simulink Topics
Prerequisites
• This example requires Simulink Coder and Embedded Coder™ .
• A Ubuntu® Linux system with ROS is necessary for building and running the generated C++ code.
You can use your own Ubuntu ROS system, or you can use the Linux virtual machine used for ROS
Toolbox examples. See “Get Started with Gazebo and Simulated TurtleBot” on page 1-205 for
instructions on how to install and use the virtual machine.
• Review the “Feedback Control of a ROS-Enabled Robot” on page 1-148 example, which details the
Simulink model that the code is being generated from.
On the Apps tab, under Control Systems, click Robot Operating System (ROS).
6-30
Generate Code to Manually Deploy a ROS Node from Simulink
In the Robot Operating System (ROS) dialog box that opens up, select Robot Operating
System (ROS) from the ROS Network drop-down. This opens up the ROS tab in the toolstrip which
shows the specified ROS Network in the Connect section.
In the Prepare section under ROS tab, click Hardware Settings to open the model configuration
parameters dialog box.
The Hardware board settings section contains settings specific to the generated ROS package,
such as information included in the package.xml file. Change Maintainer name to ROS Example
User and click OK.
In the Solver pane of the Configuration Parameters dialog, ensure the Type is set to Fixed-step,
the Solver is set to ode3 (Bogacki-Shampine)and the Fixed-step size is set to 0.05. In
generated code, the fixed-step size defines the actual time step that is used for the model update
loop. See “Execution of Code Generated from a Model” (Simulink Coder) for more information.
Click Deploy under the ROS tab. Then under Deployment, click Build Model. This setting ensures
that code is generated for the ROS node without building it on an external ROS device.
Set the current folder to a writable directory. This folder is the location that generate code will be
stored when you build the model.
Under the C Code tab, click Generate Code or press Ctrl+B to start code generation for the model.
Once the build completes, two new files are written to your folder.
6-31
6 ROS Simulink Topics
Manually transfer the two files to the target machine. If you connect to a ROS device using
rosdevice, you can send files using putFile. Otherwise, this step assumes you are using the Linux
virtual machine used for Robotics System Toolbox™ examples. The virtual machine is configured to
accept SSH and SCP connections. If you are using your own Linux system, consult your system
administrator for a secure way to transfer files.
Ensure your host system (the system with your RobotController.tgz and build_ros_model.sh
files) has an SCP client. For Windows® systems, the next step assumes that PuTTY SCP client
(pcsp.exe) is installed.
Use SCP to transfer the files to the user home director on the Linux virtual machine. Username is
user and password is password. Replace <virtual_machine_ip> with your virtual machines IP
address.
The build_ros_model.sh file is not specific to this model. It only needs to be transferred once for
multiple models.
On the Linux system, execute the following commands to create a Catkin workspace. You may use an
existing Catkin workspace. Build the Catkin workspace.
mkdir -p ~/catkin_ws_simulink/src
cd ~/catkin_ws_simulink/src
catkin_init_workspace
cd ..
catkin_make
Decompress and build the node there using the following command in Linux. Replace
<path_to_catkin_ws> with the path to your catkin workspace. If the node uses custom messages,
you must manually copy the necessary custom message packages in <path_to_catkin_ws>/msg
folder before building the node.
cd ~
./build_ros_model.sh RobotController.tgz <path_to_catkin_ws>
If that does not work, ensure that build_ros_model.sh is set up as an executable by entering the
following command.
chmod +x build_ros_model.sh
If the executable was created successfully, the command lists information about the file.
The model is now ready to be run as a standalone ROS node on your device.
Optional: You can then run the node using this command. Replace <path_to_catkin_ws> with the
path to your catkin workspace.
6-32
Generate Code to Manually Deploy a ROS Node from Simulink
~/<path_to_catkin_workspace>/devel/lib/robotcontroller/robotcontroller_node
See Also
More About
• “Feedback Control of a ROS-Enabled Robot” on page 1-148
• “Generate a Standalone ROS Node from Simulink” on page 1-194
• “Tune Parameters and View Signals on Deployed Robot Models Using External Mode” on page
6-34
6-33
6 ROS Simulink Topics
In this section...
“Set Up the Simulink Model” on page 6-34
“Deploy and Run the Model” on page 6-34
“Monitor Signals and Tune Parameters” on page 6-35
External mode enables Simulink models on your host computer to communicate with a deployed
model on your robot hardware during runtime. Use external mode to view signals or modify block
mask parameters on your deployed Simulink model. Parameter tuning with external mode helps you
make adjustments to your algorithms as they run on the hardware as opposed to in simulation in
Simulink itself. This example shows how to use external mode with the “Feedback Control of a ROS-
Enabled Robot” on page 1-148 example when the model is deployed to the robot hardware.
openExample robotROSFeedbackControlExample
1 In the Prepare section under ROS tab, click Hardware Settings to open the model
configuration parameters dialog box.
2 On the Solver pane, set Type to Fixed-step and the Fixed-step size to 0.05.
3 In Hardware Implementation > Target Hardware Resources, set the External mode
parameters. To prioritize model execution speed, enable Run external mode in a background
thread. Click OK.
In the model, add scope blocks to the signals you want to view. For this example, add an Record, XY
Graph scope to the X and Y signals that are exiting the Bus Selector from the ROS subscriber that
monitors the robot position. Open the Record block and change the minimum and maximum values
for each axis to [-10 10].
Connect to the ROS network by setting the network address. The network must be running on your
target robotics hardware. This example uses the "Gazebo Empty" simulator environment is used from
the Virtual Machine with ROS Hydro and Gazebo example. In the Simulations tab select ROS
Network to configure your ROS network address. Specify your device address by selecting Custom
under Network Address and specifying the IP address or host name under Hostname/IP Address.
For this virtual machine, the IP address is 192.168.154.131.
6-34
Tune Parameters and View Signals on Deployed Robot Models Using External Mode
Under ROS tab, click Monitor And Tune. The model is deployed to the robot hardware and runs
after the build process is complete. This step might take some time.
While the model runs on the hardware, view the Record, XY Graph window to monitor the robot
position over time.
The path has a slight wobble, which is due to the high velocity of the robot as it tracks the path.
While the model is still running, you can also tune parameters. Open the Proportional
Controller subsystem and change the Linear Velocity slider to 0.25. Back in the main model,
change the Desired Position constant block to a new position, [0 -5]. The robot drives to the new
position slower.
The lowered velocity reduces the wobble along the path. All these modifications were done while the
model was deployed on the hardware.
See Also
Related Examples
• “Feedback Control of a ROS-Enabled Robot” on page 1-148
• “Enable External Mode for ROS Toolbox Models” on page 6-38
• “Generate a Standalone ROS Node from Simulink” on page 1-194
6-35
6 ROS Simulink Topics
When connecting to a ROS device, deploying a ROS node to a ROS device, or trying to start and stop
nodes on a ROS device, you must specify the login credentials. The Connect to a ROS Device
dialog requests the following information to connect to the ROS device.
• Device Address — Specify the host name or IP address for the target ROS device.
• Username — Specify the user name that is used to log into the target ROS device.
• Password — Specify the password that is used to log into the target ROS device with the specified
user name.
• Remember my password — Select this parameter for your password to be saved for all MATLAB
sessions. If this parameter is not selected, MATLAB prompts for your password whenever a
connection to the ROS device is established.
• ROS folder — Specify the location of the ROS installation folder on the ROS device. For
example: /opt/ros/indigo
• Catkin workspace — Specify the location of the Catkin workspace folder on the ROS device. For
example: ~/catkin_ws_test
By clicking the Test button, you can verify your settings. The results of the test are displayed in the
Simulink Diagnostic Viewer. Use the Diagnostic Viewer to troubleshoot any issues with connecting to
your ROS device. For more information, see “View Diagnostics” (Simulink).
See Also
Related Examples
• “Generate a Standalone ROS Node from Simulink” on page 1-194
6-36
Enable ROS Time Model Stepping for Deployed ROS Nodes
When you enable ROS time model stepping, the deployed ROS node executes when the published
ROS time is a multiple of the base rate of the model. To enable model stepping based on ROS time:
1 On the Apps tab, under Control Systems, click Robot Operating System (ROS).
2 In the Robot Operating System (ROS) dialog box that opens up, select Robot Operating
System (ROS) from the ROS Network drop-down. This opens up the ROS tab in the toolstrip
which shows the specified ROS Network in the Connect section.
3 In the Prepare section under ROS tab, click Hardware Settings to open the model
configuration parameters dialog box. Under Target Hardware resources > ROS time, select
Enable ROS time model stepping.
To specify a topic to publish a notification when the model executes, check the Enable notification
after step check box, and use the Notification topic (default is /step_notify). Subscribe to the
topic to get a message every time ROS time is published. The ROS node publishes a std_msgs/
String message type with a string containing a '+' or '-' and the model name (+rostime_test,
for example). A '+' indicates the model was stepped. A '-' indicates the published ROS time was
not a multiple of the base rate of the model.
After enabling model stepping and setting a notification topic, you can re-build and deploy your
model. When starting the ROS node, the model waits for the ROS time to be published.
You can also enable overrun detection if the model execution is still processing when the next step is
triggered by the ROS time. For more information, see “Overrun Detection with Deployed ROS Nodes”
on page 6-39.
See Also
Current Time | Subscribe
Related Examples
• “Generate a Standalone ROS Node from Simulink” on page 1-194
• “Overrun Detection with Deployed ROS Nodes” on page 6-39
• “Get Started with ROS in Simulink” on page 1-127
• “Exchange Data with ROS Publishers and Subscribers” on page 1-60
6-37
6 ROS Simulink Topics
1 On the Apps tab, under Control Systems, click Robot Operating System (ROS).
2 In the Robot Operating System (ROS) dialog box that opens up, select Robot Operating
System (ROS) from the ROS Network drop-down. This opens up the ROS tab in the toolstrip
which shows the specified ROS Network in the Connect section.
3 In the Connect section, specify Deploy To option as Remote Device, from the drop-down. To
configure the remote device details such as IP address and user details, select Manage Remote
Device from the drop-down.
4 In the Prepare section, click Hardware Settings to open the model configuration parameters
dialog box. In Target Hardware Resources, set the External mode parameters. Click OK.
5 To build and deploy the model in external mode, under ROS tab, click Monitor And Tune.
Your model connects to the Device Address specified in the “Connect to ROS Device” on page 6-36
dialog box which is used to connect to your ROS device when deploying the model.
To configure signal monitoring and data archiving, go to the Apps tab and select External Mode
Control Panel. You can also connect to the target program and start and stop execution of the model
code. For more information, see “External Mode Simulations for Parameter Tuning, Signal
Monitoring, and Code Execution Profiling” (Simulink Coder).
See Also
Related Examples
• “Generate a Standalone ROS Node from Simulink” on page 1-194
• “Tune Parameters and View Signals on Deployed Robot Models Using External Mode” on page
6-34
• “External Mode Simulations for Parameter Tuning, Signal Monitoring, and Code Execution
Profiling” (Simulink Coder)
6-38
Overrun Detection with Deployed ROS Nodes
An overrun occurs when the deployed Simulink model is still processing the last step, but the next
step is requested.
When you enable overrun detection, the deployed ROS node notifies the user through the ROS_ERROR
logging mechanism (see ROS Logging). The error is output to the ROS console command line. To
enable overrun detection on ROS time:
1 On the Apps tab, under Control Systems, click Robot Operating System (ROS).
2 In the Robot Operating System (ROS) dialog box that opens up, select Robot Operating
System (ROS) from the ROS Network drop-down. This opens up the ROS tab in the toolstrip
which shows the specified ROS Network in the Connect section.
3 In the Prepare section under ROS tab, click Hardware Settings to open the model
configuration parameters dialog box. Under Hardware board settings > Operating system/
scheduler settings > Operating system options, select Detect task overruns.
After enabling Detect task overruns, you can re-build and deploy your model. When starting the
ROS node, the model waits for the ROS time to be published. When an overrun is detected, an error
is output to the ROS console command line, recorded in the log file, and published via /rosout. A
typical error is:
The model continues executing when the previous step finishes, and waits for the next time step.
When an overrun condition occurs, you can correct it using one of the following approaches:
See Also
Current Time | Subscribe
Related Examples
• “Generate a Standalone ROS Node from Simulink” on page 1-194
• “Enable ROS Time Model Stepping for Deployed ROS Nodes” on page 6-37
• “Get Started with ROS in Simulink” on page 1-127
• “Exchange Data with ROS Publishers and Subscribers” on page 1-60
6-39
6 ROS Simulink Topics
This model subscribes to a Pose message on the ROS network and converts it to a homogeneous
transformation. Use bus selectors to extract the rotation and translation vectors. The Coordinate
Transformation Conversion block takes the rotation vector (euler angles) and translation vector in
and gives the homogeneous transformation for the message.
Connect to a ROS network. Create a publisher for the "/pose" topic using a "geometry_msgs/
Pose" message type. Use struct message format for better efficiency.
rosinit
[pub,msg] = rospublisher("/pose","geometry_msgs/Pose","DataFormat","struct");
Specify the detailed pose information. The message contains a translation (Position) and
quaternion (Orientation) to express the pose. Send the message via the publisher.
msg.Position.X = 1;
msg.Position.Y = 2;
msg.Position.Z = 3;
msg.Orientation.X = sqrt(2)/2;
msg.Orientation.Y = sqrt(2)/2;
msg.Orientation.Z = 0;
msg.Orientation.W = 0;
send(pub,msg)
Open the "pose_to_transformation_model" model. This model subscribes to the "/pose" topic
in ROS. The bus selectors extract the quaternion and position vectors from the ROS message. The
Coordinate Transformation Conversion block then converts the position (translation) and quaternion
to a homogeneous transformation.
For more details, inspect the bus selector in the model to see how the message information is
extracted.
open_system("pose_to_transformation_model.slx")
6-40
Convert a ROS Pose Message to a Homogeneous Transformation
Modify the position or orientation components of the message. Resend the message and run model to
see the change in the homogeneous transformation.
msg.Position.X = 4;
msg.Position.Y = 5;
msg.Position.Z = 6;
send(pub,msg)
rosshutdown
6-41
6 ROS Simulink Topics
Read in a point cloud message from a ROS network. Calculate the center of mass of the coordinates
and display the point cloud as an image.
This example requires Computer Vision Toolbox® and Robotics System Toolbox®.
rosinit
Load sample messages to send including a sample point cloud message, ptcloud. Create a publisher
to send an ROS PointCloud2 message on the '/ptcloud_test' topic. Specify the message type as
'sensor_msgs/PointCloud2'. Send the point cloud message.
exampleHelperROSLoadPCloud
pub = rospublisher('/ptcloud_test','sensor_msgs/PointCloud2');
send(pub,ptcloud)
Open the Simulink® model for subscribing to the ROS message and reading in the point cloud from
the ROS.
Ensure that the Subscribe block is subscribing to the '/ptcloud_test' topic. Under the
Simulation tab, select ROS Toolbox > Variable Size Arrays and verify the Data array has a
maximum length greater than the sample image (9,830,400 points).
The model only displays the RGB values of the point cloud as an image. The XYZ output is used to
calculate the center of mass (mean) of the coordinates using a MATLAB Function block. All NaN
values are ignored.
open_system('read_point_cloud_example_model.slx')
6-42
Read A ROS Point Cloud Message In Simulink®
Run the model. The Video Viewer shows the sample point cloud as an image. The output center of
mass is [-0.2869 -0.0805 2.232] for this point cloud.
6-43
6 ROS Simulink Topics
rosshutdown
The pointCloudCOM function block contains the following code for calculating the center of mass of
the coordinates.
6-44
Read A ROS Point Cloud Message In Simulink®
comXYZ = [xMean,yMean,zMean];
end
6-45
6 ROS Simulink Topics
rosinit
Load sample messages to send including a sample image message, img. Create a publisher to send a
ROS Image message on the '/image_test' topic. Specify the message type as '/sensor_msgs/
Image'. Send the image message.
imgcell = load('imgdata.mat','img');
img = imgcell.img;
pub = rospublisher('/image_test','sensor_msgs/Image');
send(pub,img)
Open the Simulink® model for subscribing to the ROS message and reading in the image from the
ROS.
Ensure that the Subscribe block is subscribing to the '/image_test' topic. Under Simulation
tab, select ROS Toolbox > Variable Size Messages. Notice that the Use default limits for this
message type is clear. Then, in the Maximum length column, verify that the data property of the
sensor_msgs/Image message has a value greater than the number of pixels in the image (921600).
Run the model.
open_system('read_image_example_model.slx')
6-46
Read A ROS Image Message In Simulink
Run the model. The Video Viewer shows the sample image.
6-47
6 ROS Simulink Topics
rosshutdown
6-48
Generate a ROS Control Plugin from Simulink
This example shows how to generate and build a ros_control plugin from a Simulink® model. In this
example, you first configure a model to generate C++ code for a ros_control package. You then
deploy the plugin on a virtual machine running Gazebo® to control a Pioneer 3DX 2-wheeled
differential drive robot.
Prerequisites
Overview
The ros_control framework provides a generic set of tools to create controllers for various types of
robots.
This example focuses on auto-generating C++ code for a controller designed in Simulink® and
packaging it and deploying that controller as a ros_control plugin as shown in the figure below. In this
example, you generate code for a controller designed in Simulink, and deploy it as a ros_control
plugin. The data flow of the controller is shown in the following diagram.
6-49
6 ROS Simulink Topics
6-50
Generate a ROS Control Plugin from Simulink
After connecting to the ROS network, open the example controller model.
open_system('drivecontroller.slx');
The model implements a proportional controller. At each step, the algorithm orients the robot toward
the desired location and drives it forward. Once the desired location is reached, the algorithm stops
the robot.
• In MATLAB®, change the current folder to a temporary location where you have write permission.
6-51
6 ROS Simulink Topics
• ros_control interface setting prepares the model for simulation to ensure that all blocks are
properly initialized. This requires a valid connection to a ROS core.
• Start the ROS core on the virtual machine using the rosdevice object
d = rosdevice;
runCore(d);
Another roscore / ROS master is already running on the ROS device. Use the 'stopCore' function to
• Use rosinit to connect MATLAB to the ROS master running on the ROS device:
rosinit(d.DeviceAddress,11311)
The example controller model is configured for Robot Operating System (ROS). Use the ros_control
Settings button to map the output ports of the model to correct resource type.
In ROS tab, under PREPARE section, click on ROS Control Settings button from the ROS Toolbox
category.
6-52
Generate a ROS Control Plugin from Simulink
6-53
6 ROS Simulink Topics
1 Under the ROS tab, from the Deploy to drop-down, click Manage Remote Device.
2 In the Connect to a ROS device dialog that opens, enter all the information that Simulink needs
to deploy the ROS node.
3 Specify IP address or host name of your ROS device, login credentials, and the Catkin workspace.
4 Change Catkin workspace to ~/Documents/mw_catkin_ws. This workspace has a Pioneer
3DX Gazebo® world and related files to run a simulated differential drive robot.
6-54
Generate a ROS Control Plugin from Simulink
Generate C++ code for the proportional controller and create a ros_control plugin package,
automatically transfer, and build it on the ROS device.
• Configure Simulink to use the same ROS connection settings as MATLAB. Under the Simulation
tab, in Prepare section, select ROS Network. Set the ROS Master (ROS 1) and Node Host
network addresses to Default.
• Under the ROS tab, click Deploy > Build & Load. If you get any errors about bus type mismatch,
close the model, clear all variables from the base MATLAB workspace, and re-open the model.
• Click on the View Diagnostics link at the bottom of the model toolbar to see the output of the
build process.
• Once the code generation completes, the ROS package is transferred to the Catkin workspace on
the ROS device and built there.
Modify the Pioneer 3DX controller configuration YAML file to register the generated controller, and
build the workspace.
• Replace the controller configuration YAML file using the rosdevice object. To use the controller
plugin generated from the model, copy the pre-configured pioneer3dx.yaml file to the catkin
workspace.
6-55
6 ROS Simulink Topics
ans =
putFile(d,fullfile(pwd,'pioneer3dx.yaml'),[d.CatkinWorkspace,'/src/pioneer_p3dx_model/p3dx_contro
ans =
'[ 0%] Built target sensor_msgs_generate_messages_eus
[ 1%] Generating dynamic reconfigure files from cfg/controller_params.cfg: /home/user/Docum
[ 1%] Built target std_msgs_generate_messages_nodejs
[ 1%] Built target std_msgs_generate_messages_py
[ 1%] Built target roscpp_generate_messages_cpp
[ 1%] Built target rosgraph_msgs_generate_messages_nodejs
[ 1%] Built target roscpp_generate_messages_eus
Generating reconfiguration files for ControllerHost in drivecontroller
Wrote header file in /home/user/Documents/mw_catkin_ws/devel/include/drivecontroller/Control
[ 1%] Built target std_msgs_generate_messages_lisp
[ 1%] Built target roscpp_generate_messages_py
[ 1%] Built target std_msgs_generate_messages_eus
[ 1%] Built target roscpp_generate_messages_nodejs
[ 1%] Built target drivecontroller_gencfg
[ 1%] Built target std_msgs_generate_messages_cpp
[ 1%] Built target rosgraph_msgs_generate_messages_eus
[ 1%] Built target rosgraph_msgs_generate_messages_lisp
[ 1%] Built target roscpp_generate_messages_lisp
[ 1%] Built target rosgraph_msgs_generate_messages_py
[ 1%] Built target tf2_msgs_generate_messages_nodejs
[ 1%] Built target tf2_msgs_generate_messages_lisp
[ 1%] Built target tf2_msgs_generate_messages_eus
[ 1%] Built target actionlib_generate_messages_nodejs
[ 1%] Built target actionlib_generate_messages_lisp
[ 1%] Built target sensor_msgs_generate_messages_nodejs
[ 1%] Built target geometry_msgs_generate_messages_nodejs
[ 1%] Built target tf2_msgs_generate_messages_py
[ 1%] Built target geometry_msgs_generate_messages_cpp
[ 1%] Built target dynamic_reconfigure_generate_messages_cpp
[ 1%] Built target tf_generate_messages_lisp
[ 1%] Built target nav_msgs_generate_messages_cpp
[ 1%] Built target sensor_msgs_generate_messages_lisp
[ 1%] Built target nav_msgs_generate_messages_lisp
[ 1%] Built target geometry_msgs_generate_messages_eus
[ 1%] Built target dynamic_reconfigure_generate_messages_eus
[ 1%] Built target dynamic_reconfigure_gencfg
[ 1%] Built target dynamic_reconfigure_generate_messages_lisp
[ 1%] Built target actionlib_msgs_generate_messages_lisp
[ 1%] Built target dynamic_reconfigure_generate_messages_py
[ 1%] Built target nav_msgs_generate_messages_eus
[ 1%] Built target nav_msgs_generate_messages_nodejs
[ 1%] Built target actionlib_msgs_generate_messages_eus
[ 1%] Built target sensor_msgs_generate_messages_py
[ 1%] Built target geometry_msgs_generate_messages_py
[ 1%] Built target nav_msgs_generate_messages_py
[ 1%] Built target actionlib_generate_messages_eus
[ 1%] Built target actionlib_msgs_generate_messages_cpp
[ 1%] Built target rosgraph_msgs_generate_messages_cpp
6-56
Generate a ROS Control Plugin from Simulink
6-57
6 ROS Simulink Topics
• In the Ubuntu VM, click on Gazebo Pioneer 3DX desktop icon to launch the Gazebo world.
• Use rossvcclient to load the controller, sl_drivecontroller
allServices = rosservice('list');
controllerName = 'sl_drivecontroller';
loadSvcName = allServices(endsWith(allServices,'/load_controller'));
switchCtrlSvcName = allServices(endsWith(allServices,'/switch_controller'));
% Load controller
loadCtrlSvc = rossvcclient(loadSvcName{1},'DataFormat','struct','Timeout',10);
loadCtrlMsg = rosmessage(loadCtrlSvc);
loadCtrlMsg.Name = controllerName;
call(loadCtrlSvc,loadCtrlMsg)
% Start controller
switchCtrlSvc = rossvcclient(switchCtrlSvcName{1},'DataFormat','struct','Timeout',10);
swtCtrlMsg = rosmessage(switchCtrlSvc);
swtCtrlMsg.StartControllers = {controllerName};
swtCtrlMsg.Strictness = swtCtrlMsg.BESTEFFORT;
call(switchCtrlSvc,swtCtrlMsg)
• Alternatively, you can also use the rqt_controller_manager application as shown below:
6-58
Generate a ROS Control Plugin from Simulink
To move the Pioneer 3DX robot, open the set_command model and click RUN from SIMULATE
section in the SIMULATION tab. Observe the robot move in the Gazebo world.
6-59
6 ROS Simulink Topics
While the above model sends different commands, you can tune the controller parameters Gain
(Slider), Linear Velocity (Slider) and Distance Threshold, using dynamic reconfigure
framework. Use the following MATLAB code to send updated values for these parameters:
Display Parameter
dynParamSvc = rossvcclient('/p3dx/sl_drivecontroller/set_parameters',DataFormat='struct',Timeout=
msg = rosmessage(dynParamSvc);
resp = call(dynParamSvc,msg);
% List the Names and Values
for k=1:numel(resp.Config.Doubles)
disp(resp.Config.Doubles(k));
end
MessageType: 'dynamic_reconfigure/DoubleParameter'
Name: 'GainSlider_gain'
Value: 5
MessageType: 'dynamic_reconfigure/DoubleParameter'
Name: 'LinearVelocitySlider_gain'
6-60
Generate a ROS Control Plugin from Simulink
Value: 1
MessageType: 'dynamic_reconfigure/DoubleParameter'
Name: 'DistanceThreshold_const'
Value: 0.5000
for k=1:numel(resp.Config.Ints)
disp(resp.Config.Doubles(k));
end
for k=1:numel(resp.Config.Strs)
disp(resp.Config.Doubles(k));
end
for k=1:numel(resp.Config.Bools)
disp(resp.Config.Doubles(k));
end
Observe that the linear velocity of the mobile robot has increased.
With smaller velocity and distance threshold, the robot should be able to go very close to the desired
position.
Alternatively, you can also change these values from the rqt_reconfigure application on the
Virtual Machine as shown in the snapshot below:
6-61
6 ROS Simulink Topics
rosshutdown
References
6-62
Log ROS Messages from Simulink to a Rosbag Logfile
This example enables you to save ROS message data from Simulink® to a rosbag file.
A rosbag or bag is a file format in ROS for storing message data. These bags are often created by
subscribing to one or more ROS topics, and storing the received message data in an efficient file
structure. Using the ROS Logger app, you can log ROS messages from Simulink® models to rosbag
files.
Open the Simulink model. This model is configured for ROS Simulation. To configure a new model for
ROS simulation, under Apps, select Robot Operating System (ROS) and specify the appropriate
ROS network configuration parameters.
open_system("logROSMessagesFromSimulinkExampleModel")
To open the ROS Logger app dialog, under Simulation tab, from Prepare section, select ROS
Logger.
6-63
6 ROS Simulink Topics
Follow these steps to configure the signals to be logged and the rosbag file parameters:
• Ensure that Enable ROS signal logging to ROS Bag file is checked.
• Select the signals to be logged in the rosbag file by checking their respective checkboxes under
the Enable column.
• The default name of the generated rosbag file will be modelName_mmddyy_hh_mm_ss.bag. To
provide a custom name, from the Logfile name dropdown, select Custom. Then specify the
desired File name.
• Specify the Compression format to be uncompressed, bz2 or lz4.
• Specify the desired chunk size for writing, in bytes.
6-64
Log ROS Messages from Simulink to a Rosbag Logfile
sim("logROSMessagesFromSimulinkExampleModel");
After simulation, logging messages to rosbag file begins and completes with the success message on
the Diagnostic Viewer.
6-65
6 ROS Simulink Topics
Use ROS Logger app to record ROS messages during Simulink® simulation, and obtain a rosbag file
with fully synchronized ROS messages saved during simulation.
Use the prebuilt Large Parking Lot scene created using the Unreal Engine 3D simulation environment
in Simulink. To interactively select a sequence of waypoints from a scene and generate a custom
vehicle trajectory, refer to “Select Waypoints for Unreal Engine Simulation” (Automated Driving
Toolbox) example.
To configure saving options, open the ROS Logger app under SIMULATION> PREPARE> ROS
Logger. You can enable/disable ROS messages for saving, define custom file name, and rename
messages saved to rosbag file based on your preference.
6-66
Use ROS Logger App to Save ROS Messages from Simulink
After configuring with ROS Logger app, run these commands to setup model parameters and run the
simulation.
modelName = 'LogROSMessageFrom3DSimulation';
open_system(modelName);
% Configure the model to stop simulation at 5 seconds.
simStopTime = 5;
set_param(gcs, 'StopTime', num2str(simStopTime));
6-67
6 ROS Simulink Topics
sim(modelName);
After running the simulation, you can see a rosbag file generated in your current working directory.
Long running simulations take some time to generate rosbag files. You can proceed to inspect the bag
with "rosbag info" after you see the message “Successfully logged ROS bag file to…”.
rosbagViewer
Click Open and browse for the generated bag file and load it. Inspect the Topic List and Source
Details panels on the left side of the app to check the bag file info. Create Image and Point Cloud
visualizers from the toolstrip. Play the bag file to visualize the logged messages.
close(hFig)
close_system(modelName, 0)
close(hScene)
6-68
Emergency Braking of Ego Vehicle in CARLA Simulator Using Simulink and CARLA ROS Bridge
This example shows how to set up, connect to, and control an ego vehicle in the CARLA simulator
using ROS Toolbox™.
Overview
You control the CARLA ego vehicle by sending steering, braking, and throttle control signals to a
vehicle controls publisher using Simulink® software. The model reads point cloud data from the front
camera, odometer, and lidar sensors of the ego vehicle. The point cloud processor removes ground
reflection and calculates the average distance of the objects in front of the ego vehicle. The model
sends the calculated distance to the emergency braking unit which issues a braking command if the
distance drops below 10 meters.
Setup
Install the latest CARLA simulator on your host machine. This example uses the binary installation of
version 0.9.13 of the CARLA Simulator.
Download and install the ROS Virtual Machine. This virtual machine is based on the Ubuntu® Linux®
operating system and is pre-configured to support the examples in ROS Toolbox™.
6-69
6 ROS Simulink Topics
• On your windows host machine, navigate to the installed location of CARLA. Click on the
CarlaUE4.exe to start the CARLA server.
6-70
Emergency Braking of Ego Vehicle in CARLA Simulator Using Simulink and CARLA ROS Bridge
. ~/carla-ros-bridge/catkin_ws/devel/setup.bash
6-71
6 ROS Simulink Topics
• In the same terminal, run the follow command to launch the ego vehicle in the Town03
environment of CARLA simulator. The follow command launches the ego vehicle near to the gas
station.
• Run this command to change the host address to the host address of your machine:
6-72
Emergency Braking of Ego Vehicle in CARLA Simulator Using Simulink and CARLA ROS Bridge
Ensure that you can access ROS topics related to the CARLA simulator by running the following
introspection command.
rostopic list
/carla/ego_vehicle/collision
/carla/ego_vehicle/control/set_transform
/carla/ego_vehicle/enable_autopilot
/carla/ego_vehicle/gnss
/carla/ego_vehicle/lane_invasion
/carla/ego_vehicle/odometry
/carla/ego_vehicle/rgb_view/image
/carla/ego_vehicle/vehicle_control_cmd_manual
6-73
6 ROS Simulink Topics
/carla/ego_vehicle/vehicle_control_manual_override
/carla/ego_vehicle/vehicle_info
/carla/ego_vehicle/vehicle_status
/carla/status
/clock
/initialpose
/rosout
/rosout_agg
/tf
open_system('EmergencybrakingofCarlaEgoVehicle');
The model shows the point cloud data from the lidar sensor that the vehicle uses to measure the
distance to the obstacle. When the distance is below 10 meters, the emergency braking system sends
a braking command to the vehicle.
Run the Simulink model. The ego vehicle automatically stops 10 meters ahead of the vehicle in front
of it at the gas station. The CARLA ROS manual control terminal shows the stationary vehicle with
the brake applied.
6-74
Emergency Braking of Ego Vehicle in CARLA Simulator Using Simulink and CARLA ROS Bridge
rosshutdown
6-75
6 ROS Simulink Topics
This example introduces how to interact with the NVIDIA Isaac Sim® [1 on page 6-85] application
from MATLAB® through a ROS 2 interface. NVIDIA Isaac Sim, powered by Omniverse® [2 on page 6-
85], is a scalable robotics simulation application and synthetic data generation tool that powers
photorealistic, physically accurate virtual environments. You can use NVIDIA Isaac Sim to develop,
test, and manage AI-based robots. NVIDIA Omniverse is a computing platform that enables
individuals and teams to develop universal-scene-description-based (USD-based) [3 on page 6-85] 3-
D workflows and applications.
Overview
In this example, you publish ROS 2 messages from MATLAB to the Carter robot. You also subscribe to
the topics that the Carter robot publishes in MATLAB, such as odometry, image, and camera data.
This example was tested using Isaac Sim version 2022.2.1 on a Windows® platform.
Configure Workstation
1 Ensure your local workstation meets the System Requirements and Isaac Sim Driver
Requirements [4 on page 6-85] for running Omniverse Isaac Sim.
2 Visit Omniverse Downloads to download the standard version of Omniverse Launcher, which is
the native client for downloading, installing, and updating Omniverse applications, extensions,
and connectors.
3 Install Omniverse Launcher [5 on page 6-85].
4 Install Isaac Sim and Omniverse Cache [6 on page 6-85] from the Exchange tab in the
Omniverse Launcher.
5 Install Nucleus [7 on page 6-86] from the Omniverse Launcher to access Isaac environments,
assets, and samples.
1 Install the ROS 2 Foxy distribution on your Windows workstation by following the ROS 2
Windows binary installation instructions from ROS 2 Documentation: Foxy [8 on page 6-86].
2 From the start menu, look for developer command prompt: run the x64 Native Tools
Command Prompt for VS 2019 shortcut as an administrator.
3 Activate the ROS 2 environment by sourcing the ROS 2 installation. For example, run this
command in the command prompt: call C:\opt\ros\foxy\x64\setup.bat in the command
prompt.
Launch NVIDIA Isaac Sim from the same command prompt in which you activate the ROS 2
installation environment. Navigate to your Isaac Sim installation location using cd
<path_to_isaac_sim_install_path>. If you do not know where the Isaac Sim application is
installed, follow these steps to locate the installation path.
1. Go to the Library tab in the Omniverse Launcher. Select Isaac Sim in the Apps pane on the left.
6-76
Control NVIDIA Carter Robot in Isaac Sim Using ROS 2
3. Click the folder icon in the settings panel to open the Isaac Sim installation location in the explorer.
6-77
6 ROS Simulink Topics
4. Copy the Isaac Sim location and navigate to that folder in the same command prompt in which you
activate the ROS 2 environment.
6. Run isaac-sim.bat to launch Isaac Sim. The first run of the Isaac Sim application takes up to
five minutes to warm up the shader cache.
To enable the ROS 2 bridge (omni.isaac.ros2_bridge) extension, go to the Extensions menu under
the Window tab. Then, search for ROS2 Bridge and enable it. This extension connects Isaac Sim to
ROS 2.
6-78
Control NVIDIA Carter Robot in Isaac Sim Using ROS 2
2. Drag the carter_warehouse_navigation file with.usd extension to the Viewport in Isaac Sim.
This action loads a warehouse scenario containing a Carter robot that uses its RTX lidar and a camera
to perceive the world. Loading the scene for the first time takes several minutes.
6-79
6 ROS Simulink Topics
To get started, create a node in MATLAB. This action starts the ROS 2 network automatically.
node = ros2node("carterNode");
Query available topics in the ROS 2 network. Ensure that the warehouse scene is playing in NVIDIA
Isaac Sim to see the topics that the Carter robot publishes.
/camera_info_left
/clock
/cmd_vel
/odom
/parameter_events
/rgb_left
/rosout
/scan
/tf
You can control the movement of the Carter robot by publishing a message to the /cmd_vel topic.
The message must have the type geometry_msgs/Twist, which contains data specifying the linear
and angular velocities. The linear velocity along the x-axis controls forward and backward motion.
The angular velocity around the z-axis controls the rotation speed of the robot base.
velocity = 0.1;
6-80
Control NVIDIA Carter Robot in Isaac Sim Using ROS 2
Create a ROS 2 publisher for the /cmd_vel topic and the corresponding message containing the
velocity values.
robotCmd = ros2publisher(node,"/cmd_vel");
velMsg = ros2message(robotCmd);
Set the forward velocity of the robot using the velocity variable and publish the command to the
robot. Let the robot move for a moment, and then bring it to a stop.
velMsg.angular.z = 0;
velMsg.linear.x = velocity;
send(robotCmd,velMsg)
pause(4)
velMsg.linear.x = 0;
send(robotCmd,velMsg)
The Carter robot uses the /odom topic to publish its current position and orientation (collectively
referred to as pose). Because the Carter robot is not equipped with a global positioning system (GPS)
system, the pose is relative to the initial pose of the robot.
odomSub = ros2subscriber(node,"/odom");
Wait for the subscriber to return data, then extract the data and assign it to variables x, y, and z. If
the software returns an error, then the receive command likely timed out. Ensure that the robot is
publishing odometry and that your network is configured properly.
odomMsg = receive(odomSub,3);
pose = odomMsg.pose.pose;
x = pose.position.x;
y = pose.position.y;
z = pose.position.z;
[x y z]
ans = 1×3
The pose object stores the orientation of the Carter robot as a quaternion in the Orientation
property. Use quat2eul (Robotics System Toolbox) to convert the orientation to the more convenient
representation of Euler angles. Display the current orientation, theta, of the robot in degrees.
quat = pose.orientation;
angles = quat2eul([quat.w quat.x quat.y quat.z]);
theta = rad2deg(angles(1))
theta = -0.0037
Subscribe to the /rgb_left topic, on which the Carter robot publishes the camera RGB images.
6-81
6 ROS Simulink Topics
cameraSub = ros2subscriber(node,"/rgb_left");
Wait for the image data, convert the received ROS 2 message into image matrix using
rosReadImage, and then display the result by using imshow.
cameraMsg = receive(cameraSub);
I = rosReadImage(cameraMsg);
imshow(I)
Display continuously updating camera data while the Carter robot turns for a short duration.
velMsg.angular.z = velocity;
send(robotCmd,velMsg);
tic;
while toc < 20
imgMsg = receive(cameraSub);
I = rosReadImage(imgMsg);
imshow(I)
drawnow
end
6-82
Control NVIDIA Carter Robot in Isaac Sim Using ROS 2
Set the angular velocity of the robot to 0 and publish the command to the robot, for it to stop
rotating.
velMsg.angular.z = 0;
send(robotCmd,velMsg);
Subscribe to the /scan topic on which the Carter robot publishes lidar data.
lidarSub = ros2subscriber(node,"/scan");
scanMsg = receive(lidarSub);
figure
rosPlot(scanMsg)
6-83
6 ROS Simulink Topics
Continuously display updating lidar scans while the Carter robot turns for a short duration.
velMsg.angular.z = velocity;
send(robotCmd,velMsg)
tic
while toc < 20
scanMsg = receive(lidarSub);
rosPlot(scanMsg)
end
6-84
Control NVIDIA Carter Robot in Isaac Sim Using ROS 2
Set the angular velocity of the robot to 0 and publish the command to the robot, for it to stop
rotating.
velMsg.angular.z = 0;
send(robotCmd,velMsg)
References
[3] NVIDIA. “Universal Scene Description (USD) at NVIDIA.” Accessed July 27, 2023. https://
www.nvidia.com/en-us/omniverse/usd/.
[4] “1. Isaac Sim Requirements — Isaacsim Latest Documentation.” Accessed July 27, 2023. https://
docs.omniverse.nvidia.com/isaacsim/latest/requirements.html.
[5] “Installing Launcher — Launcher Latest Documentation.” Accessed July 27, 2023. https://
docs.omniverse.nvidia.com/launcher/latest/installing_launcher.html.
6-85
6 ROS Simulink Topics
[6] “Workstation — Utilities Latest Documentation.” Accessed July 27, 2023. https://
docs.omniverse.nvidia.com/utilities/latest/cache/installation/workstation.html.
[7] “Installation — Nucleus Latest Documentation.” Accessed July 27, 2023. https://
docs.omniverse.nvidia.com/nucleus/latest/workstation/installation.html.
[8] “Windows (Binary) — ROS 2 Documentation: Foxy Documentation.” Accessed July 27, 2023.
https://docs.ros.org/en/foxy/Installation/Windows-Install-Binary.html.
6-86
Read and Apply Transformation to ROS Message in Simulink
This example shows how to read transformations from ROS network and use them to transform a
pose message using Simulink®.
rosinit
• robot_base
• camera_center
• mounting_point
exampleHelperROSStartTfPublisher
[posePub,poseMsg] = rospublisher("/pose","geometry_msgs/PoseStamped",DataFormat="struct");
poseMsg.Pose.Position.X = 1;
poseMsg.Pose.Position.Y = 1;
poseMsg.Pose.Position.Z = 0.5;
send(posePub,poseMsg)
Open the readAndApplyROSTransform model. The Get Transform block reads the transformation
between the target robot_base and the source camera_center frames as a geometry_msgs/
TransformStamped bus. Then, the Apply Transform block transforms the pose message using the
read transformation value. The model then writes the transformed pose message into MATLAB®
workspace.
modelName = "readAndApplyROSTransform";
open_system(modelName)
6-87
6 ROS Simulink Topics
The readAndApplyROSTransform model uses Simulation Pacing to run at a pace where the
simulation time is same as the wall clock time. This is important to ensure that Simulink synchronizes
correctly with the transforms being published to the transformation tree in the ROS network.
out = sim(modelName);
Get transformed pose as geometry_msgs/Pose message from the simulation output variable in the
workspace.
transformedPoseMsg = helperGetTransformedROSPoseFromSimout(out);
You can visualize poses as local coordinate frames in the global cartesian coordinates. You can
calculate the location and basis axes orientation of the local frames by using the position and
orientation information in the poses, respectively. For both input and transformed poses, use the
helperGetTransformedAxesVectorsFromROSQuat function to get the basis vectors of the local
coordinate frame.
[inputPoseX,inputPoseY,inputPoseZ] = helperGetTransformedAxesVectorsFromROSQuat(poseMsg.Pose.Orie
[transformedPoseX,transformedPoseY,transformedPoseZ] = helperGetTransformedAxesVectorsFromROSQuat
Visualize the poses as local coordinate frames based on the position and orientation values. The
quiver3 function visualizes the basis vectors at the specified pose location.
quiver3(poseMsg.Pose.Position.X,poseMsg.Pose.Position.Y,poseMsg.Pose.Position.Z,inputPoseX(1),inp
hold on
quiver3(poseMsg.Pose.Position.X,poseMsg.Pose.Position.Y,poseMsg.Pose.Position.Z,inputPoseY(1),inp
quiver3(poseMsg.Pose.Position.X,poseMsg.Pose.Position.Y,poseMsg.Pose.Position.Z,inputPoseZ(1),inp
quiver3(transformedPoseMsg.Pose.Position.X,transformedPoseMsg.Pose.Position.Y,transformedPoseMsg.
quiver3(transformedPoseMsg.Pose.Position.X,transformedPoseMsg.Pose.Position.Y,transformedPoseMsg.
quiver3(transformedPoseMsg.Pose.Position.X,transformedPoseMsg.Pose.Position.Y,transformedPoseMsg.
6-88
Read and Apply Transformation to ROS Message in Simulink
legend("inputX","inputY","inputZ","transformedX","transformedY","transformedZ")
xlabel('X')
ylabel('Y')
zlabel('Z')
view([-24.39 11.31])
rosshutdown
See Also
Blocks
Get Transform | ROS Apply Transform, ROS 2 Apply Transform
Functions
rostf
6-89
6 ROS Simulink Topics
Related Examples
• “Access the tf Transformation Tree in ROS” on page 1-86
6-90
7
This example shows how to save ROS 2 message data from Simulink® to a ROS 2 Bag File.
ROS 2 bag files are used for storing message data. Their primary use occurs in the logging of
messages transmitted over a ROS 2 network. Using the ROS 2 Logger app, you can log ROS 2
messages from Simulink® models to ROS 2 bag files.
Open the Simulink model. This model is configured for ROS 2 Simulation. To configure a new model
for ROS 2 simulation, under Apps, click Robot Operating System (ROS) and select Robot
Operating System 2 (ROS 2). You can specify the appropriate ROS 2 network configuration
parameters by clicking ROS Network in Prepare section under Simulation tab in Simulink.
open_system("logROS2MessagesFromSimulinkExampleModel")
Follow these steps to configure the signals to be logged and the ROS 2 bag file parameters.
1. To log the bus signal to the ros 2 bag file, right click the bus signal and select Log Selected
Signals.
2. Open the ROS 2 Logger app dialog by selecting ROS Logger under Simulation tab from Prepare
section.
7-2
Log ROS 2 Messages from Simulink to a ROS 2 Bag File
3. Ensure that Enable ROS signal logging to ROS 2 Bag file is checked.
4. You can see the selected signal is checked under the Enable Column of the app.
5. The default name of the generated ROS 2 bag folder will be modelName_mmddyy_hh_mm_ss.db3.
To provide a custom name, from the Logfolder name dropdown, select Custom. Then specify the
desired Folder name.
6. You can also specify the Compression format, Cache size, Compression mode, Split duration,
Serialization format and Split size in the app.
7. To stop logging the selected signal, uncheck the signal in the Enable Column.
sim("logROS2MessagesFromSimulinkExampleModel");
7-3
7 ROS 2 Simulink Topics
After simulation, logging messages to ROS 2 bag file begins and completes with the success message
on the Diagnostic Viewer.
See Also
Related Examples
• “Use ROS 2 Logger App to Save ROS 2 Messages from Simulink” on page 7-5
7-4
Use ROS 2 Logger App to Save ROS 2 Messages from Simulink
Use ROS 2 Logger app to record ROS 2 messages during Simulink® simulation, and obtain a ROS 2
bag file with fully synchronized ROS 2 messages saved during simulation.
Use the prebuilt Large Parking Lot scene created using the Unreal Engine 3D simulation environment
in Simulink. To interactively select a sequence of waypoints from a scene and generate a custom
vehicle trajectory, refer to “Select Waypoints for Unreal Engine Simulation” (Automated Driving
Toolbox) example.
modelName = 'LogROS2MessageFrom3DSimulation';
open_system(modelName);
To launch ROS 2 Logger app and configure saving options, click ROS Logger in Prepare section
under Simulation. You can enable or disable ROS 2 messages for saving, define custom file name,
and rename messages saved to the ROS 2 bag file based on your preference.
7-5
7 ROS 2 Simulink Topics
After configuring with ROS 2 Logger app, run these commands to setup model parameters and run
the simulation.
7-6
Use ROS 2 Logger App to Save ROS 2 Messages from Simulink
After running the simulation, you can see a ROS 2 bag folder generated in your current working
directory. Long running simulations take some time to generate ROS 2 bag files.
Based on how you setup the "Folder name" in ROS 2 Logger app, the name of the ROS 2 bag folder
would be different. In this section, we use folderpath to represent the path to the generated bag
folder.
You can proceed to inspect the bag with "ros2("bag","info",folderpath)" after you see the
message “Successfully logged ROS 2 bag file to…”.
You can inspect the saved PointCloud2 messages with this message.
bagReader = ros2bagreader(folderpath);
bagSel = select(bagReader,"Topic","/header_assignment1");
pointCloudMsgs = readMessages(bagSel);
ptCloudXYZ = rosReadXYZ(pointCloudMsgs{1,1});
player = pcplayer([-50 100],[-50 100],[-50 100]);
ptCloud = pointCloud(ptCloudXYZ);
view(player,ptCloud);
7-7
7 ROS 2 Simulink Topics
You can also inspect the saved Image messages with this message.
bagReader = ros2bagreader(folderpath);
bagSel = select(bagReader,"Topic","/header_assignment");
imgMsgs = readMessages(bagSel);
img = rosReadImage(imgMsgs{201,1});
imshow(img)
close(hFig)
close_system(modelName, 0)
close(hScene)
See Also
“Log ROS 2 Messages from Simulink to a ROS 2 Bag File” on page 7-2
7-8
Work with ROS 2 Messages in Simulink
This example illustrates how to work with complex ROS 2 messages in Simulink®, such as messages
with nested sub-messages and variable-length arrays.
Introduction
In ROS 2 Simulink Models, bus signals represent ROS 2 Messages. Each field of a ROS 2 message is
corresponds to a field in a Simulink bus, with the following limitations:
• Constants are not supported, and are excluded from the Simulink bus.
• Variable-length arrays (ROS type ...[]) convert to fixed-length array with customizable
maximum lengths. By default, the fixed length is 128 for primitive types (e.g., uint8[],
float32[]), and 16 for nested arrays of messages (e.g., geometry_msgs/Point[]).
• Strings (ROS type string) convert to fixed-length uint8 arrays with customizable maximum
lengths, with a default maximum length of 128 characters.
• String arrays (ROS type string[]) convert to a fixed-length array of std_msgs/String with a
customizable maximum length. The default maximum length is 16 strings.
When a Simulink bus converts to a ROS 2 message, the message fields restore to their native ROS 2
types. For example, the ROS message type std_msgs/Header has a field, frame_id, which is a
string. In the corresponding Simulink bus, the frame_id field is a uint8 array. When the bus
converts to a ROS message, frame_id converts back to a string.
Model
The following model has several examples of working with complex ROS 2 messages in Simulink. The
rest of the tasks in this example focus on specific scenarios.
open_system('robotROS2MessageUsageExample');
7-9
7 ROS 2 Simulink Topics
A ROS 2 message can have arrays whose length (number of elements) cannot be pre-determined. For
example, the position field in a sensor_msgs/JointState message is a variable-length array of
64-bit floats. In any given sensor_msgs/JointState message, the position array can have no
elements or it can have an arbitrarily large number of elements. In Simulink, such arrays are
required to have a maximum length.
Open the example model and explore how variable-length arrays in ROS messages are handled in
Simulink in the following steps.
• Double-click the Work with Variable-length Arrays subsystem. Note that the Subscribe block
is configured to receive messages sent to topic /my_joint_topic as message type,
sensor_msgs/JointState.
• Under the Modeling tab, click Update Model.
• Double-click on the Bus Selector block. There are three variable-length arrays in the message
(position, velocity, and effort).
• Observe that there is a position_SL_Info field in the bus.
position_SL_Info.ReceivedLength holds the length of the Position array in the original
received ROS 2 message. This value can be arbitrarily large.
position_SL_Info.CurrentLength holds the length of the position array in the Simulink
bus signal. This can vary between 0 and the maximum length of the array (128, in this case).
7-10
Work with ROS 2 Messages in Simulink
• Under the Simulation tab, select ROS Network from the Prepare section. If you do not see ROS
Toolbox, select Robot Operating System (ROS) on the Apps tab, under Control Systems. In the
dialog box that opens up, select Robot Operating System 2 (ROS 2) from the ROS Network
drop-down.
• Set the Domain ID and RMW Implementation to desired values.
Run Simulation
• Under the Simulation tab, set Stop Time to Inf, and click Play to start simulation.
• Execute the following at the MATLAB command line.
node = ros2node("/my_node");
[pub, msg] = ros2publisher(node,"/my_joint_state", "sensor_msgs/JointState",Durability="transient
msg.position = [11:2:25]; % array of length 8
send(pub, msg);
• Observe the Display outputs in the Work with Variable-length Arrays subsystem. Note that
Current Length and Received Length are equal.
• Execute the following at the MATLAB command line.
• Observe that a warning is emitted, indicating that a truncation has happened. The Received
Length is now 130 and Current Length is 128.
• Under the Debug tab, select Diagnostics > Diagnostic Viewer. Warnings are typically routed
here to the Simulink Diagnostic Viewer (see “View Diagnostics” (Simulink)).
Change the maximum size of a variable-length array in Simulink. The default maximum of the
Position array in the sensor_msgs/JointState message type is 128. You will change this limit
to 256.
• Open the example model, and double-click on the Work with Variable-length Arrays subsystem.
• From the Simulation tab, select ROS Toolbox > Variable Size Messages.
• From the list box on the left, click on sensor_msgs/JointState. Then, unselect the Use
default limits for this message type checkbox. Finally, enter the new value (256) in the row for
the position array property, and click OK to close the dialog.
• Click Play to start simulation.
• Run the following at the MATLAB command line. Observe that a warning is not emitted in the
Diagnostic Viewer.
• Run the following at the MATLAB command line. Observe that a warning is emitted in the
Diagnostic Viewer.
7-11
7 ROS 2 Simulink Topics
Note:
The Bus Assignment block in Simulink does not support assigning to an element inside an array of
buses.
Explore how to use the MATLAB Function block for advanced message manipulation such as
assignment of nested messages.
• Open the example model. Select the Work with Nested Arrays of Messages subsystem and
copy.
• Open a new Simulink model. Paste and save the new model to a temporary location, with the name
FunctionTest.slx.
• Close all models, and clear the base workspace by typing clear in the MATLAB command line.
• Open the FunctionTest.slx model, double-click on the Work with Nested Arrays of Messages
subsystem, and open the MATLAB Function - Assign block. Observe that it uses MATLAB
notation to assign values inside a nested array.
• The Function Block requires the datatype of bus outputs (in this case, msg) to be explicitly
specified. Create all buses required for this model by typing the following at the MATLAB
command line. Note that the bus objects are created using the name SL_Bus_<messageType>
and stored in the Simulink data dictionary ros2lib. You can find this data dictionary under
External Data > From Libraries in Model Explorer.
ros.ros2.createSimulinkBus(gcs)
• Double-click the MATLAB Function - Assign block. Double-click the MATLAB Function -
Assign block. In the MATLAB Editor toolstrip, under Modeling tab, click Symbols Pane. Then
right click on msg, select Inspect and set its type to SL_Bus_geometry_msgs_PoseArray. Click
Apply and close Ports and Data Manager.
• If you do not see SL_Bus_geometry_msgs_PoseArray listed as an option in the Type dropdown,
select Refresh data types.
• If you are using variable-size messages within MATLAB Function block, you must enable Dynamic
memory allocation in MATLAB functions setting under Model Settings > Simulation
Target > Advanced parameters.
7-12
Work with ROS 2 Messages in Simulink
Run Simulation
• Under the Simulation tab, set Stop Time to 1.0, and click Play to run the simulation. Verify that
the values in the Display blocks are equal to pi/2 and pi/2 + 1.
• The ros.ros2.createSimulinkBus(gcs) statement has to be re-run each time the model is
loaded. To avoid these issues, include this statement in the InitFcn callback for the model (see
“Model Callback Parameters” (Simulink)).
By default, the maximum number of std_msgs/String messages in a string array is 16, and the
maximum length of an individual string is 128 characters. The following steps show how to change
these defaults:
Open the example model, and double-click the Work with Strings and String Arrays subsystem.
• From the Simulation tab, select ROS Toolbox > Variable Size Messages.
• In the Message types in model column, click on the sensor_msgs/JointState entry. Observe
that the right-hand pane shows a Name property that is an array of std_msgs/String, with a
maximum length of 16. To change the maximum number of strings in Name, deselect the Use
default limits for this message type checkbox and enter the desired value.
• In the Message types in model column, click on the std_msgs/String entry. Observe that the
right-hand pane shows a data property that is an array of uint8, with a maximum length of 128.
To change the maximum length of the string, deselect the Use default limits for this message
type checkbox and enter the desired value.
• Once you change the default values, open the Work with Strings and String Arrays subsystem
and simulate the model. The Display blocks should now reflect the updated maximum values.
Note: The maximum length of data applies to all instances of std_msgs/String in the model. For
example, the Blank String block in Work with Strings and String Arrays subsystem uses a
std_msgs/String message, so these messages would inherit the updated maximum length.
Likewise, if the model has another ROS message type with a string array property, the individual
strings in that array will also inherit the updated maximum length.
7-13
7 ROS 2 Simulink Topics
This example demonstrates how to receive sensor readings and autopilot status from a simulated UAV
with PX4 autopilot, and send control commands to navigate the simulated UAV.
In MATLAB®, generate custom messages for the px4_msgs package. You can add this to an existing
custom message folder and regenerate it, or generate them in this example folder. This can take some
time, as there are a large number of messages to generate.
unzip("px4_msgs.zip")
ros2genmsg("custom")
Download and connect to the virtual machine (VM) using instructions in “Get Started with Gazebo
and Simulated TurtleBot” on page 1-205. On the VM, start the simulator and PX4 Bridge by clicking
the "Gazebo PX4 SITL RTPS" desktop shortcut. This brings up a simple simulator of a quadrotor in
Gazebo.
This also brings up the Agent half of the microRTPS bridge. The Client half of the communication is
included in the PX4 Autopilot packages, and launches with the simulator.
7-14
Control a Simulated UAV Using ROS 2 and PX4 Bridge
You can enter PX4 commands on the terminal corresponding to the Gazebo simulation, but that is not
required for this example.
View the available topics that are broadcast by the bridge Agent. Notice the convention it uses to
indicate the topics it is publishes to (out) and those it is subscribing to (in).
ros2 topic list
/LaserScan/out
/clock
/fmu/collision_constraints/out
/fmu/debug_array/in
/fmu/debug_key_value/in
/fmu/debug_value/in
/fmu/debug_vect/in
/fmu/offboard_control_mode/in
/fmu/onboard_computer_status/in
/fmu/optical_flow/in
/fmu/position_setpoint/in
/fmu/position_setpoint_triplet/in
/fmu/sensor_combined/out
/fmu/telemetry_status/in
/fmu/timesync/in
/fmu/timesync/out
/fmu/trajectory_bezier/in
/fmu/trajectory_setpoint/in
/fmu/trajectory_waypoint/out
/fmu/vehicle_command/in
/fmu/vehicle_control_mode/out
/fmu/vehicle_local_position_setpoint/in
/fmu/vehicle_mocap_odometry/in
/fmu/vehicle_odometry/out
/fmu/vehicle_status/out
/fmu/vehicle_trajectory_bezier/in
/fmu/vehicle_trajectory_waypoint/in
/fmu/vehicle_trajectory_waypoint_desired/out
/fmu/vehicle_visual_odometry/in
7-15
7 ROS 2 Simulink Topics
/parameter_events
/rosout
/timesync_status
Create a node to handle the sensor input and control feedback for the UAV. Create subscribers for
sensors and information of interest, and publishers to direct the UAV in offboard control mode.
node = ros2node("/control_node");
Get the system and component IDs from the UAV status. These help direct the commands to the UAV.
This also ensures the UAV is up and running before moving into the control phase.
timeLimit = 5;
statusMsg = receive(statusSub,timeLimit);
receive(odomSub,timeLimit);
receive(timeSub,timeLimit);
Use the previously created publisher and subscriber to instruct the UAV to take off, fly to a new point,
and then land. To perform offboard control, the UAV requires control messages to be flowing
regularly (at least 2 Hz). Starting the control messages before engaging offboard mode is the easiest
way to achieve this.
7-16
Control a Simulated UAV Using ROS 2 and PX4 Bridge
You can also control the UAV using the Simulink® model ControlUAVUsingROS2. The Simulink
model includes four main subsystems: Arm, Offboard, Takeoff, and Waypoint following with obstacle
avoidance.
open_system("ControlUAVUsingROS2.slx");
A Clock block triggers different UAV activity according to the simulation time. The model arms and
enables the offboard control mode on the PX4 autopilot for the first 2 seconds. It sends out a takeoff
command to bring the UAV to 1 meter above the ground for the first 8 seconds, then it engages in
waypoint-following behavior.
7-17
7 ROS 2 Simulink Topics
You can use the control panel to enable or disable the obstacle avoidance behavior.
If obstacle avoidance is turned off, the UAV flies towards the goal point behind the obstacle box on a
straight path, resulting in a collision. If obstacle avoidance is turned on, the UAV tries to fly above the
obstacle based on the lidar sensor readings.
7-18
Control a Simulated UAV Using ROS 2 and PX4 Bridge
Once you start a fresh PX4-SITL and Gazebo instance in the VM, you can run the model and observe
the flight behavior of the UAV.
Helper Functions
function arm(timeSub,cmdPub)
% Allow UAV flight
cmdMsg = ros2message(cmdPub);
cmdMsg.command = uint32(cmdMsg.VEHICLE_CMD_COMPONENT_ARM_DISARM);
cmdMsg.param1 = single(1);
publishVehicleCommand(timeSub,cmdPub,cmdMsg)
end
function land(timeSub,cmdPub)
% Land the UAV
cmdMsg = ros2message(cmdPub);
cmdMsg.command = uint32(cmdMsg.VEHICLE_CMD_NAV_LAND);
publishVehicleCommand(timeSub,cmdPub,cmdMsg)
end
function engageOffboardMode(timeSub,cmdPub)
% Allow offboard control messages to be utilized
cmdMsg = ros2message(cmdPub);
cmdMsg.command = uint32(cmdMsg.VEHICLE_CMD_DO_SET_MODE);
cmdMsg.param1 = single(1);
cmdMsg.param2 = single(6);
publishVehicleCommand(timeSub,cmdPub,cmdMsg)
end
function publishOffboardControlMode(timeSub,controlModePub,controlType)
% Set the type of offboard control to be used
% controlType must match the field name in the OffboardControlMode message
modeMsg = ros2message(controlModePub);
modeMsg.timestamp = timeSub.LatestMessage.timestamp;
% Initially set all to false
modeMsg.position = false;
modeMsg.velocity = false;
modeMsg.acceleration = false;
modeMsg.attitude = false;
modeMsg.body_rate = false;
7-19
7 ROS 2 Simulink Topics
setpointMsg = ros2message(setpointPub);
setpointMsg.timestamp = timeSub.LatestMessage.timestamp;
setpointMsg.x = single(xyz(1));
setpointMsg.y = single(xyz(2));
setpointMsg.z = single(xyz(3));
send(setpointPub,setpointMsg)
end
function publishVehicleCommand(timeSub,cmdPub,cmdMsg)
cmdMsg.timestamp = timeSub.LatestMessage.timestamp;
cmdMsg.target_system = uint8(1);
cmdMsg.target_component = uint8(1);
cmdMsg.source_system = uint8(1);
cmdMsg.source_component = uint8(1);
cmdMsg.from_external = true;
send(cmdPub,cmdMsg)
end
7-20
Enable ROS 2 Time Model Stepping for Deployed Nodes
When you enable ROS 2 time model stepping, the deployed node executes when the published ROS 2
time is a multiple of the base rate of the model. To enable model stepping based on ROS 2 time:
1 On the Apps tab, under Control Systems, click Robot Operating System 2 (ROS 2).
2 In the Robot Operating System 2 (ROS 2) dialog box that opens up, select Robot Operating
System 2 (ROS 2) from the ROS Network drop-down. This opens up the ROS tab in the
toolstrip which shows the specified ROS Network in the Connect section.
3 In the Prepare section under ROS tab, click Hardware Settings to open the model
configuration parameters dialog box. Under Target Hardware resources > ROS 2 time, select
Enable ROS 2 time model stepping.
To specify a topic to publish a notification when the model executes, check the Enable notification
after step check box, and use the Notification topic (default is /step_notify). Subscribe to the
topic to get a message every time the ROS 2 time is published. The ROS 2 node publishes a
std_msgs/String message type with a string containing a '+' or '-' and the model name
(+ros2time_test, for example). A '+' indicates the model was stepped. A '-' indicates the
published ROS 2 time was not a multiple of the base rate of the model.
After enabling model stepping and setting a notification topic, you can re-build and deploy your
model. When starting the ROS 2 node, the model waits for the ROS 2 time to be published.
See Also
Current Time | Subscribe
Related Examples
• “Generate a Standalone ROS 2 Node from Simulink” on page 2-93
• “Get Started with ROS 2 in Simulink” on page 2-65
• “Exchange Data with ROS 2 Publishers and Subscribers” on page 2-19
7-21
7 ROS 2 Simulink Topics
This example shows how to read ROS 2 sensor_msgs/Image messages in Simulink® and perform
image registration using feature matching to estimate the relative rotation of one image with respect
to the other. This example requires Computer Vision Toolbox®.
Load two sample sensor_msgs/Image messages, imageMsg1 and imageMsg2. Create a ROS 2 node
with two publishers to publish the messages on the topics /image_1 and /image2. For the
publishers, set the quality of service (QoS) property Durability to transientlocal. This ensures
that the publishers maintain the messages for any subscribers that join after the messages have
already been sent. Publish the messages using the send function.
load('ros2ImageMsgs.mat');
node = ros2node('/image_test');
imgPub1 = ros2publisher(node,'/image1','sensor_msgs/Image',Durability='transientlocal',Depth=2);
imgPub2 = ros2publisher(node,'/image2','sensor_msgs/Image',Durability='transientlocal',Depth=2);
send(imgPub1,imageMsg1);
send(imgPub2,imageMsg2);
Read messages from ROS 2 Network in Simulink and Perform Image Registration
modelName = 'readImageAndEstimateTransformationExampleModel.slx';
open_system(modelName);
Ensure that the two Subscribe blocks are connected to the topics, /image1 and /image2. The value
of the Durability QoS parameter of the Subscribe blocks is Transient local. This ensures
compatibility with the QoS settings of the publishers that you configured in the previous section. The
messages from the subscribers are fed to the Read Image blocks to extract the image data, which is
7-22
Read ROS 2 Image Messages in Simulink® and Perform Registration using Feature Matching
Under Simulation tab, select ROS Toolbox > Variable Size Messages. Notice that the Use
default limits for this message type is clear. Then, in the Maximum length column, verify that
the data property of the sensor_msgs/Image message has a value greater than the number of
pixels in the image (921600). Run the model.
sim(modelName);
The model performs image registration, estimates the 2D transformation and displays the relative
rotation (deg) of the image published on /image2 topic, with respect to that on /image1. It also
visualizes the two images along with the matched inlier points and the /image2 image transformed
into the view of the /image1 image.
7-23
7 ROS 2 Simulink Topics
1 Detect and extract ORB features and corresponding valid points in the two images using
detectORBFeatures (Computer Vision Toolbox) and extractFeatures (Computer Vision
Toolbox).
2 Find candidate matches and collect the actual corresponding point locations from both the
images using matchFeatures (Computer Vision Toolbox).
3 Estimate the relative geometric transformation between the two images along with inliers using
estimateGeometricTransform2D (Computer Vision Toolbox), which implements the M-
estimator sample consensus (MSAC), a variant of the random sample consensus (RANSAC)
algorithm.
4 Compute and output the relative rotation from the estimated geometric transformation.
For more information about local feature detection and extraction such as different kinds of feature
detectors, see “Local Feature Detection and Extraction” (Computer Vision Toolbox). Feature matching
is also a key initial step in Visual SLAM applications. For an overview of the Visual SLAM workflow
using MATLAB™, see “Implement Visual SLAM in MATLAB” (Computer Vision Toolbox).
%% Feature Matching
% Find candidate matches
indexPairs = matchFeatures(featuresImage1,featuresImage2,'Unique',true,'MaxRatio',0.6,'MatchT
sz = size(indexPairs);
7-24
Read ROS 2 Image Messages in Simulink® and Perform Registration using Feature Matching
%% Transform estimation
% Estimate the transformation matrixbetween the two images based on matched points
[tform,inlierIdx] = estimateGeometricTransform2D(matchedPointsImage2,matchedPointsImage1,'sim
figure
% subplot(2,1,2)
outputView = imref2d(size(img1));
img3 = imwarp(img2,tform,'OutputView',outputView);
imshowpair(img1,img3,'montage');
title('Image 2 (right) transformed to the view of Image 1')
end
7-25
7 ROS 2 Simulink Topics
This example shows how to read ROS 2 PointCloud2 messages into Simulink® and reconstruct a 3-
D scene by combining multiple point clouds using the normal distributions transform (NDT)
algorithm. This example requires Computer Vision Toolbox®.
load("ros2PtcloudMsgs.mat");
node = ros2node("/point_cloud_publisher");
ptcloudPub1 = ros2publisher(node,"/ptcloud1","sensor_msgs/PointCloud2",Durability="transientlocal
ptcloudPub2 = ros2publisher(node,"/ptcloud2","sensor_msgs/PointCloud2",Durability="transientlocal
send(ptcloudPub1,ptcloudMsg1)
send(ptcloudPub2,ptcloudMsg2)
Read Messages from ROS 2 Network in Simulink and Perform Point Cloud Stitching
modelName = "read_pointcloud_and_perform_stitching_example_model.slx";
open_system(modelName)
7-26
Read ROS 2 Point Cloud Messages in Simulink and Perform Stitching Using Registration
Ensure that the two Subscribe blocks are connected to the topics, /ptcloud1 and /ptcloud2. The
value of the Durability QoS parameter of the Subscribe blocks is Transient local. This ensures
compatibility with the QoS settings of the publishers that you configured in the previous section. The
messages from the subscribers are fed to the Read Point Cloud blocks to extract the point cloud data,
which is then fed to the registerAndStitchPointclouds MATLAB Function block to perform
registration and stitching.
Under Simulation tab, select ROS Toolbox > Variable Size Messages. Notice that the Use
default limits for this message type is clear. Then, in the Maximum length column, verify that
the data property of the sensor_msgs/PointCloud2 message has a value greater than the number
of points in the pointcloud (4915200). Run the model.
sim(modelName);
The model performs point cloud registration using the NDT algorithm and estimates the 3-D
transformation of the point cloud published on the /ptcloud2 topic, with respect to the point cloud
published on the /ptcloud1 topic. Next, it transforms the /ptcloud2 point cloud to the reference
coordinate system of the /ptcloud1 point cloud. It then stitches the transformed point cloud with
the /pcloud1 point cloud to create the 3-D world scene. It also visualizes the two point clouds along
with the world scene.
7-27
7 ROS 2 Simulink Topics
1 Downsample the point clouds with a 10 cm grid filter to speed up registration and improve
accuracy by using the pcdownsample (Computer Vision Toolbox) function.
2 Align the two downsampled point clouds using pcregisterndt (Computer Vision Toolbox),
which uses the NDT algorithm to estimate the 3-D rigid transformation of second pointcloud with
respect to the first point cloud.
3 Transform the second point cloud to the reference frame of the first point cloud using the
pctransform (Computer Vision Toolbox) function.
4 Merge the transformed point cloud and the first point cloud with a 1.5 cm box grid filter by using
the pcmerge (Computer Vision Toolbox) function.
5 Visualize the two point clouds and the reconstructed 3-D world scene.
For more information about registering and stitching point clouds, see “3-D Point Cloud Registration
and Stitching” (Computer Vision Toolbox). Registration is also a key initial step in point cloud SLAM
applications. For an overview of the point cloud SLAM workflow using MATLAB, see “Implement Point
Cloud SLAM in MATLAB” (Computer Vision Toolbox).
% Transform and align the frame of point cloud 2 to the frame of point cloud 1
pCloudAligned = pctransform(pcloud2,tform);
% Visualize the two point clouds and the merged point clouds
subplot(2,2,1)
pcshow(pcloud1.Location,pcloud1.Color,VerticalAxis="Y",VerticalAxisDir="Down");
title("Point Cloud 1")
view(0,-90);
subplot(2,2,2)
7-28
Read ROS 2 Point Cloud Messages in Simulink and Perform Stitching Using Registration
pcshow(pcloud2.Location,pcloud2.Color,VerticalAxis="Y",VerticalAxisDir="Down");
title("Point Cloud 2")
view(0,-90);
subplot(2,2,[3,4])
pcshow(ptCloudScene.Location,ptCloudScene.Color,VerticalAxis="Y",VerticalAxisDir="Down");
title("Merged Point Cloud")
view(0,-90);
end
7-29
7 ROS 2 Simulink Topics
This example shows how to call a service on the ROS 2 network in Simulink® using the Call Service
block and receive a response.
node_1 = ros2node(exampleHelperCreateRandomNodeName);
Create a service that adds two integers using the exiisting service type example_interfaces/
AddTwoInts. Specify the callback function to be exampleHelperROS2SumCallback which
performs the addition of numbers in the a and b fields of the service request message.
sumserver = ros2svcserver(node_1,"/sum","example_interfaces/AddTwoInts",@exampleHelperROS2SumCall
Open the Simulink model with the Call Service block. Use the Blank Message block to output a
request message with the example_interfaces/AddTwoIntsRequest message type. Populate the
bus with two values to sum together. You can ignore warnings about converting data types.
open_system("AddTwoIntsROS2ServiceExampleModel.slx")
Run the model. The service call should return -2 from the Resp output port, as part of the sum field
in the response message. An error code of 0 indicates that the service call was successful.
sim("AddTwoIntsROS2ServiceExampleModel.slx");
7-30
Read A ROS Scan Message In Simulink®
This example shows how to read in a laser scan message from a ROS network. Calculate the points in
Cartesian coordinates and visualize with a 2D plot.
rosinit
Load a sample ROS LaserScan message. Create a publisher for the topic /scan and specify the
message type as sensor_msgs/LaserScan. Publish the sample LaserScan message on this topic.
exampleHelperROSLoadScan
pub = rospublisher("/scan","sensor_msgs/LaserScan",DataFormat="struct");
send(pub,scan)
Open the Simulink® model for subscribing to a published message and reading the scan message
from ROS.
open_system("read_scan_example_model.slx")
The model reads the LaserScan message from the ROS network. The Read Scan block extracts
range and angle data from the message. These are then fed to the plotXY MATLAB Function block
which converts the ranges and angles to points in Cartesian coordinates and visualizes them on a
plot. All NaN values are ignored.
Run the model. The plot shows the points in the laser scan.
7-31
7 ROS 2 Simulink Topics
rosshutdown
7-32
Write A ROS Image Message In Simulink®
This example shows how to write a image message and publish it to a ROS network in Simulink®.
rosinit
Load a sample image. Create a subscriber to receive a ROS Image message on the /image topic.
Specify the message type as sensor_msgs/Image and the data format as struct.
exampleHelperROSLoadImageData
sub = rossubscriber("/image","sensor_msgs/Image",DataFormat="struct");
Open the Simulink® model for writing and publishing ROS Image message.
open_system("write_image_example_model.slx");
Ensure that the Publish block is publishing to the /image topic. Under the Simulation tab, select
ROS Toolbox > Variable Size Arrays and verify the Data array has a maximum length greater than
the length of the Data field in img (921,600).
The model writes the input img to a ROS Image message. Using a Header Assignment block, the
frame ID of the message header is set to /camera_depth_optical_frame.
sim("write_image_example_model.slx");
The image message is published to the ROS network and received by the subscriber created earlier.
You can use the rosReadImage function to retrieve the image in a format that is compatible with
MATLAB.
imageFormatted = rosReadImage(sub.LatestMessage);
The sample image has an rgb8 encoding. By default, rosReadImage returns the image in a standard
480-by-640-by-3 uint8 format. View this image using the imshow function.
7-33
7 ROS 2 Simulink Topics
figure
imshow(imageFormatted)
close_system("write_image_example_model.slx",0);
rosshutdown
7-34
Write A ROS Point Cloud Message In Simulink®
This example shows how to write a point cloud message and publish it to a ROS network in
Simulink®.
rosinit
Load the 3D coordinate locations and color data for the sample point cloud. Create a subscriber to
receive a ROS PointCloud2 message from the /point_cloud topic. Specify the message type as
sensor_msgs/PointCloud2 and the data format as a struct.
exampleHelperROSLoadPointCloudData
sub = rossubscriber("/point_cloud","sensor_msgs/PointCloud2",DataFormat="struct");
Open the Simulink® model for writing a ROS point cloud message and publishing it to a ROS
network.
open_system("write_point_cloud_example_model.slx");
Ensure that the Publish block is publishing to the /point_cloud topic. Under the Simulation tab,
select ROS Toolbox > Variable Size Arrays and verify the Data array has a maximum length
greater than the length of the Data field in ptcloud (9,830,400).
The model writes the color and location data to a ROS point cloud message. Using a Header
Assignment block, the frame ID of the message header is set to /camera_rgb_optical_frame.
sim("write_point_cloud_example_model.slx");
The point cloud message is published to the ROS network and received by the subscriber created
earlier. Visualize the point cloud with the rosPlot function. rosPlot automatically extracts the x-,
y-, and z- coordinates and shows them in a 3-D scatter plot. The rosPlot function ignores points with
NaN values for coordinates regardless of the presence of color values at those points.
7-35
7 ROS 2 Simulink Topics
rosPlot(sub.LatestMessage);
close_system("write_point_cloud_example_model.slx",0);
rosshutdown
7-36
Get and Set ROS 2 Parameters in Simulink
This example shows how to use ROS 2 parameters in Simulink® and share data over the ROS 2
network.
modelName = "GetAndSetROS2Parameters";
open_system(modelName)
This model uses the Get Parameter block to create a parameter myparam. The parameter is
associated with the ROS 2 node that the Simulink model creates during simulation. You can specify
the initial value of myparam in the block parameters for the Get Parameter block.
To set the parameter associated with the Simulink model during the simulation, you must use
programmatic commands to run simulation. Start the simulation.
set_param(modelName,"SimulationCommand","start")
Pause the simulation to obtain the name of the ROS 2 node created by the Simulink model. Create a
ros2param object for the node, to access its parameters.
set_param(modelName,"SimulationCommand","pause")
if get_param(modelName,"SimulationStatus") == "paused"
nodelist = ros2("node","list");
simNodeArr = strfind(nodelist,modelName);
simNodeIdx = find(~cellfun(@isempty, simNodeArr));
simNodeName = nodelist{simNodeIdx};
paramObj = ros2param(simNodeName);
end
7-37
7 ROS 2 Simulink Topics
Continue the simulation. At each timestep, get the current value of the parameter by using the get
object function on ros2param object. Then, set the new value of the parameter using the set object
function. Observe the Scope showing the parameter value increase by 1 every simulation time step.
set_param(modelName,"SimulationCommand","step")
while get_param(modelName,"SimulationStatus") == "paused"
% Get and set parameter
[currParam,status] = get(paramObj,"myparam");
if status
set(paramObj,"myparam",currParam+1);
end
set_param(modelName,"SimulationCommand","step")
end
7-38
Get and Set ROS 2 Parameters in Simulink
7-39
7 ROS 2 Simulink Topics
This example shows how to time stamp a ROS 2 message with the current system time of your
computer. Use the Current Time block and assign its output to the stamp field of a std_msgs/
Header message. Publish the message on a desired topic.
Open the model. The model uses a Bus Assignment block to add the Current Time output to the
stamp field of the ROS 2 message.
open_system("current_time_ros2_example_model.slx")
Run the model. The Publish block should publish the Header message with the current system time.
sim("current_time_ros2_example_model.slx");
7-40
Update Header Field of a ROS 2 Message in Simulink
This example illustrates how to update the header field of a ROS 2 message using Simulink®.
Some ROS 2 messages contain a specific header field which maps to std_msgs/Header message
type. The header field contains timestamp and coordinate frame information of the ROS 2 message.
This example model shows how to use the ROS 2 Header Assignment block to update that information
for a ROS 2 message, in Simulink.
open_system('ros2HeaderAssignmentExampleModel.slx')
The Blank Message block creates an empty ROS 2 message of type, sensor_msgs/LaserScan. Any
other message type that contains a header field of std_msgs/Header can be used here, instead. The
output of the Blank Message block is then fed to the ROS 2 Header Assignment block, which updates
the header field of this message. For display, the frame_id and stamp values of the updated ROS 2
message header are selected from the list of bus elements uisng Bus Selector blocks.
Open the ROS 2 Header Assignment block to display its block parameters. The Set Frame ID option
is selected and the name of the coordinate frame that is associated with the message is specified in
the text box as lidar_link. This will be set as the frame_id value for the Header. The Set
Timestamp option is also selected which sets the stamp value of the Header to the current ROS 2
System time, by default. The Header field name option is set to Use the default Header
field name because, the name of the Header field in a blank message is its default value, header.
If you are using a ROS 2 message with a custom name for the Header field, you can select the
Specify your own option from the dropdown and specify the name of the Header field in the text
box.
Run the model. Observe the updated values for the frame_id and stamp fields of ROS 2 message in
their repective displays.
sim('ros2HeaderAssignmentExampleModel');
7-41
7 ROS 2 Simulink Topics
7-42
Read and Apply Transformation to ROS 2 Message in Simulink
This example shows how to read transformations from ROS 2 network and use them to transform a
pose message using Simulink®.
node = ros2node("/node1");
• robot_base
• camera_center
• mounting_point
exampleHelperROS2StartTfPublisher
[posePub,poseMsg] = ros2publisher(node,"/pose","geometry_msgs/PoseStamped",Durability="transientl
poseMsg.pose.position.x = 1;
poseMsg.pose.position.y = 1;
poseMsg.pose.position.z = 0.5;
send(posePub,poseMsg)
Open the readAndApplyROS2Transform model. The Get Transform block reads the transformation
between the target robot_base and the source camera_center frames as a geometry_msgs/
TransformStamped bus. Then, the Apply Transform block transforms the pose message using the
read transformation value. The model then writes the transformed pose message into MATLAB®
workspace.
modelName = "readAndApplyROS2Transform";
open_system(modelName)
7-43
7 ROS 2 Simulink Topics
The readAndApplyROS2Transform model uses Simulation Pacing to run at a pace where the
simulation time is same as the wall clock time. This is important to ensure that Simulink synchronizes
correctly with the transforms being published to the transformation tree in the ROS 2 network.
out = sim(modelName);
Get transformed pose as geometry_msgs/Pose message from the simulation output variable in the
workspace.
transformedPoseMsg = helperGetTransformedROS2PoseFromSimout(out);
You can visualize poses as local coordinate frames in the global cartesian coordinates. You can
calculate the location and basis axes orientation of the local frames by using the position and
orientation information in the poses, respectively. For both input and transformed poses, use the
helperGetTransformedAxesVectorsFromROS2Quat function to get the basis vectors of the local
coordinate frame.
[inputPoseX,inputPoseY,inputPoseZ] = helperGetTransformedAxesVectorsFromROS2Quat(poseMsg.pose.ori
[transformedPoseX,transformedPoseY,transformedPoseZ] = helperGetTransformedAxesVectorsFromROS2Qua
Visualize the poses as local coordinate frames based on the position and orientation values. The
quiver3 function visualizes the basis vectors at the specified pose location.
quiver3(poseMsg.pose.position.x,poseMsg.pose.position.y,poseMsg.pose.position.z,inputPoseX(1),inp
hold on
quiver3(poseMsg.pose.position.x,poseMsg.pose.position.y,poseMsg.pose.position.z,inputPoseY(1),inp
quiver3(poseMsg.pose.position.x,poseMsg.pose.position.y,poseMsg.pose.position.z,inputPoseZ(1),inp
quiver3(transformedPoseMsg.pose.position.x,transformedPoseMsg.pose.position.y,transformedPoseMsg.
quiver3(transformedPoseMsg.pose.position.x,transformedPoseMsg.pose.position.y,transformedPoseMsg.
quiver3(transformedPoseMsg.pose.position.x,transformedPoseMsg.pose.position.y,transformedPoseMsg.
legend("inputX","inputY","inputZ","transformedX","transformedY","transformedZ")
xlabel('X')
7-44
Read and Apply Transformation to ROS 2 Message in Simulink
ylabel('Y')
zlabel('Z')
view([-24.39 11.31])
See Also
Blocks
Get Transform | ROS Apply Transform, ROS 2 Apply Transform
Functions
ros2tf
Related Examples
• “Access the tf Transformation Tree in ROS 2” on page 2-48
7-45
8
This example shows how to use deep convolutional neural networks inside a ROS enabled Simulink®
model to perform lane and vehicle detection. In this example, you first read traffic video as the input
and publish the frames as sensor_msgs/Image messages to a topic on the ROS network. Then you
detect vehicles, and the left and right lane boundaries corresponding to the ego vehicle in every
frame, annotate the input image with the detections, and publish them to a topic in the ROS network.
Finally, you generate CUDA® optimized code for the ROS node from the Simulink model for lane and
vehicle detection.
This example uses the pretrained lane detection network from the Lane Detection Optimized with
GPU Coder example of GPU Coder Toolbox™. For more information, see “Lane Detection Optimized
with GPU Coder” (GPU Coder).
This example also uses the pretrained vehicle detection network from the Object Detection Using
YOLO v2 Deep Learning example of Computer Vision Toolbox™. For more information, see Object
Detection Using YOLO v2 Deep Learning.
Third-Party Prerequisites
Overview
This example uses three Simulink models, which are each represented as ROS nodes.. The following
diagram illustrates their interaction. The rosImagePublisher node reads the raw video file and
converts the frame data into a ROS image. The laneAndVechicleDetection node performs lane
and vehicle detection and publishes the annotated image. The annotateImageDisplay node
displays the annotated images as a video stream.
8-2
Lane and Vehicle Detection in ROS Using YOLO v2 Deep Learning Algorithm
The laneAndVehicleDetection model performs lane and vehicle detection as shown. When lane
images are being published to the topic /rawlaneimgs, the model runs the detection algorithm on
them and publishes the annotated images to a different topic. For a more detailed explanation of Lane
Detection, Vehicle Detection or Annotation using Vehicle Bounding Boxes and Lane Trajectory
subsystems, see Lane and Vehicle Detection in Simulink Using Deep Learning.
Run Simulation
8-3
8 ROS CUDA Simulink Topics
Open the Configuration Parameters dialog box of the laneAndVehicleDetection model. In the
Simulation Target pane, select GPU acceleration. In the Deep Learning section, select the target
library as cuDNN. Alternatively, you can set the parameters using the following commands.
set_param('laneAndVehicleDetection','GPUAcceleration','on');
set_param('laneAndVehicleDetection','SimDLTargetLibrary','cudnn');
set_param('laneAndVehicleDetection','DLTargetLibrary','cudnn');
8-4
Lane and Vehicle Detection in ROS Using YOLO v2 Deep Learning Algorithm
In the Hardware Implementation pane, select Robot Operating System (ROS) for Hardware
Board and specify Device Vendor and Device Type.
8-5
8 ROS CUDA Simulink Topics
In the Code Generation pane, select the Language as C++ and enable Generate GPU code.
set_param('laneAndVehicleDetection','TargetLang','C++');
set_param('laneAndVehicleDetection','GenerateGPUCode','CUDA');
8-6
Lane and Vehicle Detection in ROS Using YOLO v2 Deep Learning Algorithm
In the Code Generation > Libraries > GPU Code pane, enable cuBLAS, cuSOLVER and cuFFT.
set_param('laneAndVehicleDetection','GPUcuBLAS','on');
set_param('laneAndVehicleDetection','GPUcuSOLVER','on');
set_param('laneAndVehicleDetection','GPUcuFFT','on');
8-7
8 ROS CUDA Simulink Topics
To configure ROS node deployment on your local host machine, in the Connect section of the ROS
tab, set Deploy to Localhost. Click the Build and Run button from ROS tab to deploy the node. At
the end of the build process, you will see the ROS node running on local host machine. Then, run
annotatedImageDisplay model, you should be able to view the annotated image video in the
Video Viewer output.
Related Topics
8-8
Generate CUDA ROS Node from Simulink
Configure Simulink® Coder™ to generate and build a CUDA® ROS node from a Simulink model. You
configure the model to simulate and generate CUDA code for ROS node. You then deploy the CUDA
ROS node to local or remote device targets.
Prerequisites
• Install and set up these MathWorks® products and support packages: Simulink Coder (required),
Embedded Coder® (recommended), GPU Coder™, and GPU Coder Interface for Deep Learning
(required for deep learning).
• You can also install MATLAB® Coder™ Support Package for NVIDIA® Jetson™ and NVIDIA
DRIVE™ Platforms (required for NVIDIA hardware connection).
• Development computer with CUDA-enabled NVIDIA GPU.
• Your target device can be a local host computer with a CUDA-enabled NVIDIA GPU, or a remote
device such as an NVIDIA Jetson board.
• To use GPU Coder for CUDA code generation, you must install NVIDIA graphics driver, CUDA
toolkit, cuDNN library, and TensorRT library. For more information, see “Installing Prerequisite
Products” (GPU Coder).
• To set up the environment variables, see “Setting Up the Prerequisite Products” (GPU Coder).
• To ensure you have the required third-party software, see “ROS Toolbox System Requirements”.
To verify that your development computer has the drivers, tools, libraries, and configuration required
for GPU code generation, enter these commands in the MATLAB Command Window:
gpuEnvObj = coder.gpuEnvConfig;
gpuEnvObj.BasicCodegen = 1;
gpuEnvObj.BasicCodeexec = 1;
gpuEnvObj.DeepLibTarget = "tensorrt";
gpuEnvObj.DeepCodeexec = 1;
gpuEnvObj.DeepCodegen = 1;
results = coder.checkGpuInstall(gpuEnvObj)
results =
8-9
8 ROS CUDA Simulink Topics
gpu: 1
cuda: 1
cudnn: 1
tensorrt: 1
basiccodegen: 1
basiccodeexec: 1
deepcodegen: 1
deepcodeexec: 1
tensorrtdatatype: 1
profiling: 0
• Open the Simulink model you want to configure for GPU code generation.
• From the Simulation tab, in the Prepare section, expand the gallery and, under Configuration
& Simulation, select Model Settings.
• From the left pane of the Configuration Parameters dialog box, select the Hardware
Implementation node. Set Hardware Board to Robot Operating System (ROS) and specify
the Device Vendor and Device Type for your hardware. Expand Device details and verify that
Support long long is selected.
8-10
Generate CUDA ROS Node from Simulink
• In the Simulation Target node, select GPU acceleration. If your model has deep learning
blocks, then, under Deep Learning, select the appropriate Target library.
• Select the Code Generation node. Under Target selection, set Language to C++, and select
Generate GPU code.
• If your model has deep learning blocks, expand the Code Generation node and select the
Interface node. Then, under in Deep Learning select the appropriate value for Target library.
8-11
8 ROS CUDA Simulink Topics
• Select the GPU Code node and, under Libraries, enable cuBLAS, cuSOLVER, and cuFFT.
To generate and deploy a CUDA ROS node to a ROS device, follow the steps in the “Generate a
Standalone ROS Node from Simulink” on page 1-194 example.
Limitations
Related Topics
• “Lane and Vehicle Detection in ROS Using YOLO v2 Deep Learning Algorithm” on page 8-2
• “Sign Following Robot Using YOLOv2 Detection Algorithm with ROS in Simulink” on page 2-114
8-12
Play Back Data from ROS 2 Bag Logfile in Simulink
Use the Read Data block to play back data from a ROS 2 bag logfile.
Load Model
open_system("read_pose_log.slx")
Set up Model
1 Open the Read Data block mask to load a ROS 2 bag logfile (.db3).
2 Click the Load logfile data link.
3 Browse for the logfile and specify a time offset or limited duration if needed. The ros2_bag.db3
file and the associated metadata.yaml file are attached to this example.
4 Select the desired topic, /odom which contains nav_msgs/Odometry messages.
5 The Read Data block outputs the messages from the ROS 2 bag logfile.
6 A bus selector extracts the xy-position from the nav_msgs/Odometry messages.
Run Model
The block plays back data in sync with the simulation time. The Record plot displays the robot
position over time.
8-13
8 ROS CUDA Simulink Topics
sim(gcs)
8-14
9
Configure Simulink® Coder™ to generate and build a CUDA® ROS 2 node from a Simulink model.
You configure the model to simulate and generate CUDA code for ROS 2 node. You then deploy the
CUDA ROS 2 node to local or remote device targets.
Prerequisites
• Install and set up these MathWorks® products and support packages: Simulink Coder (required),
Embedded Coder® (recommended), GPU Coder™, and GPU Coder Interface for Deep Learning
(required for deep learning).
• You can also install MATLAB® Coder™ Support Package for NVIDIA® Jetson™ and NVIDIA
DRIVE™ Platforms (required for NVIDIA hardware connection).
• Development computer with CUDA-enabled NVIDIA GPU.
• Your target device can be a local host computer with a CUDA-enabled NVIDIA GPU, or a remote
device such as an NVIDIA Jetson board.
• To use GPU Coder for CUDA code generation, you must install NVIDIA graphics driver, CUDA
toolkit, cuDNN library, and TensorRT library. For more information, see “Installing Prerequisite
Products” (GPU Coder).
• To set up the environment variables, see “Setting Up the Prerequisite Products” (GPU Coder).
• To ensure you have the required third-party software, see “ROS Toolbox System Requirements”.
To verify that your development computer has the drivers, tools, libraries, and configuration required
for GPU code generation, see “Setting Up the Prerequisite Products” (GPU Coder).
results =
9-2
Generate CUDA ROS 2 Node from Simulink
gpu: 1
cuda: 1
cudnn: 1
tensorrt: 1
basiccodegen: 1
basiccodeexec: 1
deepcodegen: 1
deepcodeexec: 1
tensorrtdatatype: 1
profiling: 0
• Open the Simulink model you want to configure for GPU code generation.
• From the Simulation tab, in the Prepare section, expand the gallery and, under Configuration
& Simulation, select Model Settings.
• From the left pane of the Configuration Parameters dialog box, select the Hardware
Implementation node. Set Hardware Board to Robot Operating System 2 (ROS 2) and
specify the Device Vendor and Device Type for your hardware. Expand Device details and
verify that Support long long is selected.
9-3
9 ROS 2 CUDA Simulink Topics
• In the Simulation Target node, select GPU acceleration. If your model has deep learning
blocks, then, under Deep Learning, select the appropriate Target library.
9-4
Generate CUDA ROS 2 Node from Simulink
• Select the Code Generation node. Under Target selection, set Language to C++, and select
Generate GPU code.
9-5
9 ROS 2 CUDA Simulink Topics
• If your model has deep learning blocks, expand the Code Generation node and select the
Interface node. Then, under in Deep Learning select the appropriate value for Target library.
9-6
Generate CUDA ROS 2 Node from Simulink
• Select the GPU Code node and, under Libraries, enable cuBLAS, cuSOLVER, and cuFFT.
9-7
9 ROS 2 CUDA Simulink Topics
To generate and deploy a CUDA ROS 2 node to a ROS 2 device, follow the steps in the “Generate a
Standalone ROS 2 Node from Simulink” on page 2-93 example.
Limitations
9-8