ROS2 interfaces are the messages and services you use with your topics and services.
ROS2 - Msg and Srv
- use msg primitive types to create a message definition
- create a message definition using other message definitions
Topic:
- Name:
/number_count
- Msg definition:
example_interfaces/msg/int64
Service:
- Name:
/reset_number_count
- Srv definition:
example_interfaces/srv/SetBool
Create and Build Your First Custom Msg
cd /ros2_ws/src
ros2 pkg create my_robot_interfaces
cd my_robot_interfaces/
rm -rf include/
rm -rf src/
mkdir msg
In package.xml
<!-- functionalities to build interfaces -->
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
In CMakeLists.txt
# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/HardwareStatus.msg"
)
ament_export_dependencies(rosidl_default_runtime)
ament_package()
Then start build a first msg
cd msg/
# use uppercase for new word, no msg inside the name
touch HardwareStatus.msg
In HardwareStatus.msg
int64 temperature
bool are_motors_ready
string debug_message
Then build the package
cd /ros2_ws
colcon build --packages-select my_robot_interfaces
test
source ~/.bashrc
ros2 interface show my_robot_interfaces/msg/HardwareStatus
Use Your Custom Msg in a Python Node
add installed custom msg to the dependencies
in package.xml
<depend>rclpy</depend>
<depend>example_interfaces</depend>
<depend>my_robot_interfaces</depend>
add python autocomplete path in settings.json in VScode and restart it
"python.autoComplete.extraPaths": [
"~/ros2_ws/install/my_robot_interfaces/local/lib/python3.10/dist-packages/my_robot_interfaces/"
]
create a publisher that use this custom msg
Create new python file in my_py_pkg:
touch hw_status_publisher.py
chmod +x hw_status_publisher.py
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from my_robot_interfaces.msg import HardwareStatus
class HardwareStatusPublisherNode(Node):
def __init__(self):
super().__init__("hardware_status_publisher")
self.hw_status_publisher_ = self.create_publisher(
msg_type=HardwareStatus, topic="hardware_status", qos_profile=10)
self.get_logger().info("Hardware status publisher has been started!")
def publish_hw_status(self):
msg = HardwareStatus()
msg.temperature = 45
msg.are_motors_ready = True
msg.debug_message = "Nothing special here"
self.hw_status_publisher_.publish(msg)
def main(args=None):
rclpy.init(args=args)
node = HardwareStatusPublisherNode(Node)
rclpy.spin(node)
rclpy.shutdown()
if __name__ == "__main__":
main()
In setup.py
entry_points={
'console_scripts': [
"py_node = my_py_pkg.my_first_node:main", # executable
"robot_news_station = my_py_pkg.robot_news_station:main",
"smartphone = my_py_pkg.smartphone:main",
"add_two_ints_server = my_py_pkg.add_two_ints_server:main",
"add_two_ints_client = my_py_pkg.add_two_ints_client:main",
"hw_status_publisher = my_py_pkg.hw_status_publisher:main"
],
},
build package, run the node, test the result
# terminal 1
cd /ros2_ws
colcon build --packages-select my_py_pkg --symlink-install
ros2 run my_py_pkg hw_status_publisher
# terminal 2
source ~/.bashrc
ros2 node list
ros2 topic list
ros2 topic echo /hardware_status
useful commands for debug:
ros interface package list
ros2 interface package sensor_msgs
# find node name
ros2 node list
# find interface name
ros2 node info /hardware_status_publisher
# find msg
ros2 interface show my_robot_interfaces/msg/HardwareStatus
ros2 topic list
ros2 topic info /hardware_status
ros2 interface show my_robot_interfaces/msg/HardwareStatus
ros2 service list
ros2 service type /add_two_ints
ros2 interface show example_interfaces/srv/AddTwoInts