This tutorial is created by Robotics Ambassador Christian
Unit 1 Introduksyon sa Kurso
– Buod –
Tinatayang Oras na Kakailanganin: 30 minuto
Mabuhay!
Sa maikling gabay na ito, ating dadaluban kung ano nga ba ang mga ROS2 Messages at paano natin magagamit ang mga ito sa ating paggawa ng mga robots.
Bilang gabay sa mga tatalakayin ng proyektong ito, sila ay nakalista bilang mga sumusunod:
1. Introduksyon sa Kurso 1.1 Mga Pangangailangan sa Kurso at mga Sanggunian 2. Pagpapahayag ng Konsepto ng ROS2 Messages 3. Praktikal na Halimbawa: Paggawa ng Sariling Message at Paggamit nito sa uganayang publisher-subscriber
– Dulo ng Buod –
Unit 1.1 Mga Pangangailangan sa Kurso at mga Sanggunian
Para sa kursong ito, tinataya ng may-akda na may kaalaman ka na sa pangunahing operasyong pang-terminal ng mga sistemang gumagana sa Ubuntu 22.04 LTS na OS at maging sa pangunahing nabigasyon and commands na ginagamit sa mga Linux terminals. Kung nais mo pang matuto ng mga programming fundamentals na kailangan para sa pag-aral ng ROS, mangyaring tumungo at tignan ang kursong Code Foundation for ROS Learning Path ng The Construct! Tiyak na matututunan mo ang lahat ng kailangan mong kaalaman upang masimulan mo na ang paggamit ng ROS!
At kung interesado ka na rin sa kung paano gumawa ng mga packages at nodes sa ROS2, mangyaring tignan mo na rin ang gabay na ito: How to Create Packages and Nodes in ROS2
Sa tutorial na ito, Gagamitin natin ang ROSject platform na handog ng TheConstruct! Subalit, kung nais niyong gumamit ng sariling virtual machine o computer, mangyaring gawing gabay ang OS-to-Distribution compatibilities na siyang ibinahagi ng opisyal na dokumentasyon ng ros.org para sa ROS2 Humble Hawksbill
* ROS2 Humble Hawksbill: PC o Virtual Machine na may Ubuntu 22.04 LTS
Unit 2: ROS2 Messages – Ano nga ba sila?
Sa kasalukuyan ay dapat pamilyar na tayo sa konsepto ng mga topics sa ROS2. Kung ating babalikan ang naging halimbawa noong nakaraan, ang mga ROS2 topics ay siyang mga nagsisilbing lagusan ng impormasyon kung saan maaari itong gamitin ng mga subscriber para mapatakbo ang isang feature ng robot. Ngayon naman’y ating dadaluban ang isa sa mga mahalagang aspeto ng mga ito at ito ang mga messages!
Sa ROS2, may tatlong pangunahing uri ng interface — ang messages, services, at actions. Sa gabay na ito, ating tatalakayin ang mga messages. Sa madaling salita, ang mga dokumentong ito ang siyang naglalaman ng mga variables na gagamitin ng ating robot o program hinggil sa pagpapagana ng naturang feature. Isang magandang halimbawa na nito ay ang Twist() message na gamit natin upang bigyan ng velocities and ating turtlesim.
Kung ating sisiyasatin ang laman ng Twist() message type, ito ang ating masisilayan: Vector3 linear Vector3 angular
At sa loob ng bawat Vector, ito naman ang laman nila:
Ibigsabihin nito ay mayroong tatlong posibleng velocities na pwedeng ipublish gamit ang message na ito. Ang mga linear velocities ay siyang tumutkoy sa paharap at palikod, pagilid, at pataas na galaw ng robot; habang ang mga angular naman ay tinatawag na pitch, yaw, at roll. Para sa mga groundbot, ang madalas gamitin na angular velocity ay ang yaw; habang para sa mga robot na panghimpapawid ay ginagamit ang anim na yan dahil mas marami ang kanilang Degrees of Freedom (DoF).
Ngayon, kung ating papansinin ang pagsulat ng mga messages sa ROS2, masasabi nating napakasimple ng kanilang istruktura. Ang tanging kailangan lamang na ilagay ay yung klase ng variable at yung pangalan nito — at hinggil naman sa pagpapangalan, dapat ay masimulan lamang ito sa kapital ng letra at ang file extension ay ‘.msg’.
<variable type> <variable name>
Ngayon at alam na natin kung ano sila, halina’t ating simulan ang paggawa at paggamit ng ating mga customized na ROS2 messages!
Unit 3: Paggawa ng Sariling Message at Paggamit nito sa Uganayang Publisher-Subscriber
Bilang panimula, tayo muna ay gumawa ng ating Workspaces folder na siyang maglalaman ng lahat ng ating workspace para sa ROS2.
# Sa Terminal 1
user:~$ mkdir Workspaces
Matapos niyan ay gumawa tayo ng workspace na ating papangalanang sample_ws. Mangyaring patakbuhin na rin ang ‘colcon build’ pagkatapos sa loob nito.
# Sa Terminal 1
user:~/Workspaces$ mkdir sample_ws
user:~/Workspaces$ colcon build
Para sa gabay na ito, gagawa tayo ng dalawang packages — una ay ating tatawaging ‘my_interface_pkg’ na siyang maglalaman ng ating custom message at ang isa naman ay ating tatawagin ‘use_custom_interface_pkg’ kung saan natin gagawin ang mga publisher at subscriber na gagamit ng ating nagawang interface.
Ngayon ay ating unahin muna ang ‘my_interface_pkg’
# Sa Terminal 1
user:~/Workspaces$ cd sample_ws
user:~/Workspaces/sample_ws$ mkdir src
user:~/Workspaces/sample_ws$ cd src
user:~/Workspaces/sample_ws/src$ ros2 pkg create my_interface_pkg --build-type ament_cmake --dependencies std_msgs rclcpp
Isang mahalagang konseptong alalahanin ay sa tuwing gagawa ng package para sa mga interfaces ay dapat na ament_cmake ang build type ng mga ito at nakadepende sa rclcpp. Subalit para sa paggawa ng nodes ay malaya tayong pumili kung nais nating gumamit ng python o cpp na environment.
Kasunod ng paggawa ng package ay gumawa tayo ng folder na ating papangalanang ‘msg’ sa loob ng my_interface_pkg. Mula rito ay gumawa na rin tayo ng ating message file na ating papangalanang ‘Numbers.msg’
# Sa Terminal 1
user:~/Workspaces/sample_ws/src$ cd my_interface_pkg
user:~/Workspaces/sample_ws/src/my_interface_pkg$ mkdir msg
user:~/Workspaces/sample_ws/src/my_interface_pkg$ cd msg
user:~/Workspaces/sample_ws/src/my_interface_pkg/msg$ touch Numbers.msg
Mangyaring kopyahin ang naturang code sa ilalim na siyang magiging laman ng Numbers.msg
int32 a
int32 b
Tumungo sa CMakeList.txt na file at idagdag ang sumusunod na mga linya:
cmake_minimum_required(VERSION 3.8)
project(my_interface_pkg)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rosidl_default_generators REQUIRED)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/Numbers.msg"
)
ament_package()
Ngayon naman ay tumungo sa package.xml at idagdag ang mga sumusunod na sipi ng code:
Siguraduhing na-save ang lahat ng mga file at i-compile ang naturang package
# Terminal 1
user:~/Workspaces/sample_ws/src/my_interface_pkg/msg$ cd ../../../
user:~/Workspaces/sample_ws$ colcon build
Ngayon naman ay tumungo tayo sa paggawa ng publisher at subscriber na gagamit ng ating custom message.
Una, gumawa ng python package na ating papangalanang ‘use_custom_interface_pkg’
# Sa Terminal 1
user:~/Workspaces/sample_ws$ cd src
user:~/Workspaces/sample_ws/src$ ros2 pkg create use_custom_interface_pkg --build-type ament_python --dependencies rclpy std_msgs geometry_msgs my_interface_pkg
Para sa ating mga codes, atin itong ilalagay sa loob ng /use_custom_interface_pkg/use_custom_interface_pkg na directory at papangalanan natin ang publisher at subscriber bilang sumusunod:
Matapos i-code ang mga ito, mangyaring muling i-compile ang kabuuan ng ‘sample_ws’. At ngayon, atin nang patakbuhin ang ating mga nagawang node na gumagamit ng ating custom message!
# Sa Terminal 1
user:~/Workspaces/sample_ws/src/use_custom_interface_pkg/cd use_custom_interface_pkg$ cd ../../../
user:~/Workspaces/sample_ws$ colcon build
Para sa bahaging ito, i-source ang terminal 2 and 3 para sa sample_ws
# Sa Terminal 2 at 3
user:~$ cd Workspaces/sample_ws
user:~/Workspaces/sample_ws$ source install/setup.bash
Patakbuhin ang publisher at subscriber sa Terminal 2 at 3
# Sa Terminal 2
user:~/Workspaces/sample_ws$ ros2 run use_custom_interface_pkg custom_publisher
# Sa Terminal 3
user:~/Workspaces/sample_ws$ ros2 run use_custom_interface_pkg custom_subscriber
Ganito dapat ang lalabas sa iyong pagpapatakbo:
[INFO] [1711264604.204593355] [custom_subscriber]: Received Numbers: a=3, b=8, sum=11
[INFO] [1711264604.204593546] [custom_subscriber]: Received Numbers: a=3, b=5, sum=8
[INFO] [1711264604.187348953] [custom_subscriber]: Received Numbers: a=2, b=3, sum=5
[INFO] [1711264604.237378829] [custom_subscriber]: Received Numbers: a=4, b=4, sum=8
[INFO] [1711264604.142367827] [custom_subscriber]: Received Numbers: a=1, b=6, sum=7
...
[INFO] [1711264604.204593355] [custom_subscriber]: Received Numbers: a=7, b=9, sum=16
[INFO] [1711264604.204593355] [custom_subscriber]: Received Numbers: a=3, b=1, sum=4
At ayan!
Matagumpay nating nagawa ang ating custom message sa ROS2 at magamit ang mga ito sa publisher at subscriber! Kapag tapos ka nang magsiyasat, maaarin mong pindutin ang “ctrl + c” upang patayin na ang naturang node at maging ang simulation. At diyan nagtatapos ang ating maikling gabay hinggil sa paggawa ng custom messages! Nawa’y may natutunan kayong bago na makatutulong sa inyong pag-aaral ng ROS!
Para sa iba pang mga ROSject na tulad nito, mangyaring bisitahin ang The Construct. Nag-aalok sila ng napakaraming praktikal na mga gabay sa ROS mula sa mga payak hanggang sa mga konseptong pangbihasa na!
Hanggang sa muli! Ito si Christian C. Anabeza, ang inyong Filipino ROSbotics Ambassador!
Let’s assume you wish to wash your clothing. There are two possible ways you could go about it:
Go to the Laundry service provider
Put your clothes to wash.
Wait until the clothes are washed.
Get your clothes.
If you have a washing machine at home:
Put your clothes to wash
Instead of waiting, you can do other things and leave the watching machine doing its jobs
Check once in a while if the clothes are finished
Do other things.
Clothes are washed.
Option 1 is a blocking activity because you have to wait (in theory not able to do anything else) for the clothes to be washed, while option 2 is non-blocking because you can do some other things while your clothes are being washed.
This non-blocking is what defines an Action. If ROS2 Services are for instant request-responses, an Action is a task that may take a lot of time to be finished, and in the meantime, a robot (or you) is free to do other things and is also able to constantly check the status of the action.
Opening the rosject
In order to learn how to create an and use an Action Server in ROS2, we need to have ROS2 installed in our system, and it is also useful to have some simulations. To make your life easier, we already prepared a rosject with a simulation for that: https://app.theconstructsim.com/#/l/4a1c58c5/.
You can download the rosject on your own computer if you want to work locally, but just by copying the rosject (clicking the link), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject (below you have a rosject example).
Learn ROS2 – Run rosject (example of the RUN button)
After pressing the Run button, you should have the rosject loaded. Let’s now head to the next section to really get some real practice.
Launching the simulation
The rosject we provided contains the packages needed to run a TurtleBot3 simulation in ROS2. The TurtleBot3 has the following sensors:
Lidar
IMU
Feel free to use this rosject to test your mobile robot programs.
The rosject is structured the following way:
turtlebot3_ws: this workspace contains the TurtleBot3 packages provided by ROBOTIS. Don’t modify this unless you know what you are doing and want to change something from the simulation
Use this workspace to develop your programs
Assuming you have opened the rosject by clicking the Run button, we can launch the simulation with:
After a few seconds, the simulation should have opened automatically:
[ROS2 How-to] #2 – Create a ROS2 action server – Simulation running
In case the simulation does not pop up automatically, you can easily click the Open Gazebo button like in the example below (bear in mind that the simulation below is not the one used in this tutorial. Its main purpose is to show the Open Gazebo button):
Open Gazebo by clicking Open Gazebo
Creating our ROS2 package (later used to create our Action Server)
Let’s create our ROS2 Package. For that, let’s start by opening a new terminal:
Open a new Terminal
In the terminal that was just open, by running the “ls” command you can see that we have at least the following folders:
ros2_ws turtlebot3_ws
The turtlebot3_ws contains the simulation, and the ros2_ws is where we are going to place our code.
Before you continue, it is worth mentioning that in the rosject that we shared with you, the custom_interfaces package that we are going to create here already exists. We are going to create it here basically for learning purposes. You would actually not need it since the package was already created for you:
Let’s create a package named custom_interfaces with the action_msgs std_msgs rosids_default_generators packages as dependencies:
After the package was created, let’s create a folder called action:
mkdir -p custom_interfaces/action/
and also create the action/Patrol.action file.
touch custom_interfaces/action/Patrol.action
This is the file/Interface that we will use in our Action Server for patrolling.
Let’s now open that Patrol.action file. You can open it in the Code Editor. If you do not know how to open the Code Editor, please check the image below:
Open the IDE – Code Editor
You can now open the custom_interfaces/action/Patrol.action file and paste the following content on it:
In the end, the final CMakeLiss.txt file would look like the following:
cmake_minimum_required(VERSION 3.8)
project(custom_interfaces)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(action_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)
set(action_files
"action/Patrol.action"
)
rosidl_generate_interfaces(${PROJECT_NAME}
${action_files}
DEPENDENCIES action_msgs std_msgs
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
ament_package()
And for the file custom_interfaces/package.xml we also have to add the following code before the <export> tag:
So far so good. ROS is able to find our custom interface.
The time has now come for us to create the Action Server.
Creating our ROS2 Action Server
Let’s create a different package for the Action Server, just to keep things separated. Since we are not doing to create Interfaces in this new package, just use existing interfaces, let’s use the ament_python build type. Again, bear in mind that if you are using the rosject that we provided, the package already exists in the ~/ros2_ws/src folder:
Let’s now open that file using the Code Editor, and paste the following content to it:
#!/usr/bin/env python3
#
# Copyright 2019 ROBOTIS CO., LTD.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Authors: Ryan Shim, Gilbert
import math
import time
import rclpy
from geometry_msgs.msg import Twist
from rclpy.action import ActionServer
from rclpy.action import CancelResponse
from rclpy.action import GoalResponse
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.duration import Duration
from rclpy.node import Node
from rclpy.qos import QoSProfile
from rclpy.executors import MultiThreadedExecutor
from custom_interfaces.action import Patrol
class Turtlebot3PatrolServer(Node):
def __init__(self):
super().__init__('turtlebot3_patrol_server')
self.goal = Patrol.Goal()
qos = QoSProfile(depth=10)
# Initialise publishers
self.cmd_vel_pub = self.create_publisher(Twist, 'cmd_vel', qos)
# Initialise servers
self._action_server = ActionServer(
self,
Patrol,
'patrol',
execute_callback=self.execute_callback,
callback_group=ReentrantCallbackGroup(),
goal_callback=self.goal_callback,
cancel_callback=self.cancel_callback)
self.get_logger().info("Turtlebot3 patrol action server has been initialised.")
def destroy(self):
self._action_server.destroy()
super().destroy_node()
def goal_callback(self, goal_request):
# Accepts or rejects a client request to begin an action
self.get_logger().info('Received goal request :)')
self.goal = goal_request
return GoalResponse.ACCEPT
def cancel_callback(self, goal_handle):
# Accepts or rejects a client request to cancel an action
self.get_logger().info('Received cancel request :(')
return CancelResponse.ACCEPT
async def execute_callback(self, goal_handle):
self.get_logger().info('Executing goal...')
radius = self.goal.radius # unit: m
speed = 0.5 # unit: m/s
feedback_msg = Patrol.Feedback()
total_driving_time = 2 * math.pi * radius / speed
feedback_msg.time_left = total_driving_time
last_time = self.get_clock().now()
# Start executing an action
while (feedback_msg.time_left > 0):
if goal_handle.is_cancel_requested:
goal_handle.canceled()
self.get_logger().info('Goal canceled')
return Patrol.Result()
curr_time = self.get_clock().now()
duration = Duration()
duration = (curr_time - last_time).nanoseconds / 1e9 # unit: s
feedback_msg.time_left = total_driving_time - duration
self.get_logger().info('Time left until the robot stops: {0}'.format(feedback_msg.time_left))
goal_handle.publish_feedback(feedback_msg)
# Give vel_cmd to Turtlebot3
twist = Twist()
twist = self.drive_circle(radius, speed)
self.cmd_vel_pub.publish(twist)
# Process rate
time.sleep(0.010) # unit: s
# When the action is completed
twist = Twist()
self.cmd_vel_pub.publish(twist)
goal_handle.succeed()
result = Patrol.Result()
result.success = True
self.get_logger().info('Returning result: {0}'.format(result.success))
return result
def drive_circle(self, radius, velocity):
self.twist = Twist()
self.linear_velocity = velocity # unit: m/s
self.angular_velocity = self.linear_velocity / radius # unit: rad/s
self.twist.linear.x = self.linear_velocity
self.twist.angular.z = self.angular_velocity
return self.twist
def main(args=None):
rclpy.init(args=args)
patrol_action_server = Turtlebot3PatrolServer()
# Use a MultiThreadedExecutor to enable processing goals concurrently
executor = MultiThreadedExecutor()
rclpy.spin(patrol_action_server, executor=executor)
patrol_action_server.destroy()
rclpy.shutdown()
if __name__ == '__main__':
main()
The code used above is just an adaptation of a code already provided by ROBOTIS.
Before we compile our code, we also have to open the patrol_action_server/setup.py file and modify the entry_points section to define our executable called patrol_action_server_exe in the following way:
We can now run our server with the following commands:
source install/setup.bash
ros2 run patrol_action_server patrol_action_server_exe
The server should start with no problems:
[INFO] [1651528559.914166370] [turtlebot3_patrol_server]: Turtlebot3 patrol action server has been initialised
Calling our ROS2 Action Server
Ok, if you did not kill the Action Server launched in the previous section, please open a second terminal that we will use to call the Action Server.
With “ros2 node list” we should be able to find our node running:
ros2 node list
/turtlebot3_patrol_server
And with ros2 action list, we should be able to see the /patrol action:
ros2 action list
/patrol
We can now call our Action Server. If you remember when we created the Patrol.action, we defined a radius. Let’s them call the Action Server passing a radius of 0.5. The robot will be basically rotating:
You should now see the feedback sent by the action server:
Waiting for an action server to become available...
Sending goal:
radius: 0.5
Goal accepted with ID: dd32bc835d7a4ef5ae854d0bfb4b119f
Feedback:
time_left: 6.2831525802612305
Feedback:
time_left: 6.271763801574707
Feedback:
time_left: 6.260392665863037
Feedback:
time_left: 6.2484917640686035
Feedback:
time_left: 6.237414836883545
Feedback:
time_left: 6.2265496253967285
Feedback:
time_left: 6.215761661529541
...
^CCanceling goal...
Feedback:
time_left: 5.634908676147461
Goal canceled.
Remember that you can easily cancel the call to the action server by pressing CTRL+C.
If you look at the simulation after sending a goal to the Action Server, you should see the robot spinning around 0.5 meters.
Congratulations. You now know how to create a ROS2 Action Server from scratch. If you want more details about the code of the Action Server, please check the video in the next section.
Youtube video
So this is the post for today. Remember that we have the live version of this post on YouTube. If you liked the content, please consider subscribing to our youtube channel. We are publishing new content ~every day.
Keep pushing your ROS Learning.
Related Courses & Training
If you want to learn more about ROS and ROS2, we recommend the following courses:
In order to better understand ROS2 Interfaces, we need to have ROS2 installed in our system, and sometimes it is also useful to have some simulations. To make your life easier, we already prepared a rosject that you can use, with ROS2 already installed: https://app.theconstructsim.com/#/l/4a5c5215/.
You can download the rosject on your own computer if you want to work locally, but just by copying the rosject (clicking the link), you will have a setup already prepared for you.
After the rosject has been successfully copied to your own area, you should see a Run button. Just click that button to launch the rosject (below you have a rosject example).
Learn ROS2 – Run rosject (example of the RUN button)
After pressing the Run button, you should have the rosject loaded. Let’s now head to the next section to really get some real practice.
ROS2 Interfaces overview
ROS2 Interfaces is a common language behind ROS2 messages, services, and actions.
Let’s start listing the interfaces. For that, let’s first open a terminal:
Open a new Terminal
After the terminal is open, you can list the interfaces with the command ros2 interface list. The output would be something similar to the following:
As you can see in the output above, the same command returned Messages, Actions, and Services.
Creating our first ROS2 Interface (a message)
If you are using the rosject provided at the beginning of this post, there is already a ROS2 Package called checking_interfaces on the /home/user/ros2_ws/src/checking_interfaces path. The package also already contains a message on the ~/ros2_ws/src/checking_interfaces/msg/NewMsg.msg path.
If you are not using the provided rosject, you can create a package with:
If you are using the rosject you do not need to create the message msg/NewMsg.msg, but for learning purposes, let’s see how to create it.
~/ros2_ws/src/checking_interfaces$ ls ~/ros2_ws/src/checking_interfaces$ ls msg/NewMsg.msg
cd ~/ros2_ws/src/checking_interfaces
mkdir msg
cd msg
touch NewMsg.msg
Then, paste the following content on the NewMsg.msg file:
bool check
int16 number
string text
If you are wondering how to know which types are accepted for the properties of the new message, the types available are:
ROS2 build-in-types
Type name
C++
Python
DDS type
bool
bool
builtins.bool
boolean
byte
uint8_t
builtins.bytes*
octet
char
char
builtins.str*
char
float32
float
builtins.float*
float
float64
double
builtins.float*
double
int8
int8_t
builtins.int*
octet
uint8
uint8_t
builtins.int*
octet
int16
int16_t
builtins.int*
short
uint16
uint16_t
builtins.int*
unsigned short
int32
int32_t
builtins.int*
long
uint32
uint32_t
builtins.int*
unsigned long
int64
int64_t
builtins.int*
long long
uint64
uint64_t
builtins.int*
unsigned long long
string
std::string
builtins.str
string
wstring
std::u16string
builtins.str
string
Compiling our ROS2 Interface
In order to compile our ROS2 Interface, we have to touch the ~/ros2_ws/src/checking_interfaces/CMakeLists.txt file. Again, if you are using the rosject we provided, everything is already prepared for you. For learning purposes, let’s open the file to modify it. Let’s start by opening the Code Editor:
Open the IDE – Code Editor
After the Code Editor is open, feel free to open the checking_interfaces/CMakeListst.txt file.
Around line 13 of the CMakeListst.txt file, we have to add the following lines:
The first line mentioned above includes the rosidl_default_generators package, which will be used to “compile” our message to make it available for Python and C++, so that our nodes can use the interface.
In the rosidl_generate_interfaces we add the name of the interface (message, service, or action) that we want to compile, which in this case is “msg/NewMsg.msg”.
After setting up the CMakeLists.txt file, you also have to set up the checking_interfaces/package.xml file. We have to add rosidl_default_generators as a build dependency, we also need to add the rosidl_default_runtime execution dependency, and we also need the rosidl_interface_packages “member of group”. In the end, the lines you would need to add are:
After saving the files, you can compile the interface with:
cd ~/ros2_ws/
colcon build --packages-select checking_interfaces
The package should compile with no errors:
...
This may be promoted to an error in a future release of colcon-core.
Starting >>> checking_interfaces
Finished <<< checking_interfaces [5.27s]
Summary: 1 package finished [5.87s]
After the package is compiled, we can now source the installation folder so that ROS can find what we have compiled so far:
source install/setup.bash
If we now list the interfaces again and search for our NewMsg, we should be able to find it:
ros2 interface list | grep New
# ...
checking_interfaces/msg/NewMsg
# ...
As we can see in the output above, we have a message called NewMsg.
Using the interface we just created
If we have just created the checking_interfaces/msg/NewMsg, we should be able to use it. We can check its definition with:
ros2 interface show checking_interfaces/msg/NewMsg
which shows the exact thing we defined in the NewMsg.msg file:
bool check
int16 number
string text
Let’s now create a publisher in a topic called /testing using this message:
Similar to when defining our message, we already have a service defined on ~/ros2_ws/src/checking_interfaces/srv/NewServiceMessage.srv, but we will be following the process for learning purposes in case you are not using the rosject we provided, or wants to learn with hands-on.
cd ~/ros2_ws/src/checking_interfaces
mkdir srv
cd srv
touch NewServiceMessage.srv
You can now open the NewServiceMessage.srv file with the Code Editor and paste the following content on it:
bool check
---
int16 number
string text
In order to compile the service interface, you have to open the CMakeLists.txt file again and add “srv/NewServiceMessage.srv” right after “msg/NewMsg.msg” that we added earlier around line 15 of our CMakeLists.txt file. The rosidl_generate_interfaces section of the file would be like:
As you can see so far, the same rosidl_generate_interfaces is used to compile Messages and Services.
You may have noticed that we have a line containing “—“ in the NewServiceMessage.srv file. These three “—” basically separate the Service Request from the Service Response.
The request will be “bool check“, and the fields used in a response will be “int16 number” and “string text“.
After saving the file changes, we can just compile the service interface in the same way that we compiled the message interface:
cd ~/ros2_ws/
colcon build --packages-select checking_interfaces
source install/setup.bash
If you now list the interfaces, you should be able to easily find our NewServiceMessage.
ros2 interface list | grep New
checking_interfaces/msg/NewMsg
checking_interfaces/srv/NewServiceMessage
Congratulations. You now know how to easily create ROS2 Interfaces. Please go ahead and try to create ROS2 Action Interfaces yourself, or you can also check the courses that we have listed at the end of this post.
Youtube video
So this is the post for today. Remember that we have the live version of this post on YouTube. If you liked the content, please consider subscribing to our youtube channel. We are publishing new content ~every day.
Keep pushing your ROS Learning.
Related Courses & Training
If you want to learn more about ROS and ROS2, we recommend the following courses: