DEV Community

Jiaju_Xie
Jiaju_Xie

Posted on

One small experience to check the node of ros2

talk and subscribe

base 24.02 ubuntu
jazzy ros2

check the version of ros2
echo $ROS_DISTRO
which ros2

1 Ctrl + Alt + T open the first terminal
2 source /opt/ros/jazzy/setup.bash
3 mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
// create package in src workplace ,not in the root
4 creat python package
ros2 pkg create --build-type ament_python my_py_pubsub --dependencies rclpy std_msgs

5 dive into the package dic
cd ~/ros2_ws/src/my_py_pubsub

6
creat talker and listenser code file
cd ~/ros2_ws/src/my_py_pubsub/my_py_pubsub
touch talker.py listener.py

7
talker.py

import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class TalkerNode(Node):
    def __init__(self):
        super().__init__('talker_node')
        self.publisher_ = self.create_publisher(String, 'chatter', 10)
        self.timer = self.create_timer(1.0, self.timer_callback)
        self.count = 0

    def timer_callback(self):
        msg = String()
        msg.data = f'Hello World: {self.count}'
        self.publisher_.publish(msg)
        self.get_logger().info(f'Publishing: "{msg.data}"')
        self.count += 1


def main(args=None):
    rclpy.init(args=args)
    node = TalkerNode()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()
Enter fullscreen mode Exit fullscreen mode

8
talker.py

import rclpy
from rclpy.node import Node
from std_msgs.msg import String


class ListenerNode(Node):
    def __init__(self):
        super().__init__('listener_node')
        self.subscription = self.create_subscription(
            String,
            'chatter',
            self.listener_callback,
            10
        )

    def listener_callback(self, msg):
        self.get_logger().info(f'I heard: "{msg.data}"')


def main(args=None):
    rclpy.init(args=args)
    node = ListenerNode()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()
Enter fullscreen mode Exit fullscreen mode

9 in the first terminal
cd ~/ros2_ws
colcon build --packages-select my_py_pubsub
source ~/ros2_ws/install/setup.bash
ros2 run my_py_pubsub listener

10 in the second terminal
source /opt/ros/jazzy/setup.bash
source ~/ros2_ws/install/setup.bash
ros2 run my_py_pubsub talker

explain:
这个实验本质上做了什么?

先说结论。

我们刚刚做的事情,本质上是:

建了一个 ROS 2 工作空间

在这个工作空间里创建了一个 Python 类型的 ROS 2 包

在这个包里写了两个节点:

talker.py

listener.py

再通过 colcon build 让 ROS 2 识别这个包

最后通过 ros2 run 运行节点

所以,这不是“随便写了两个 Python 文件”,而是:

我们创建了一个最小的 ROS 2 Python 示例包,用来验证发布/订阅通信机制。

ROS 2 的思路是:

写 node → 放进 package → 放进 workspace → build → 用 ros2 run 运行

*workplace : ros2_ws/ *

以后你可以在这个 workspace 里放很多个 ROS 2 包,比如:

my_py_pubsub

my_robot_control

my_camera_pkg

src/ 是源码目录。

自己写的包,通常都放在这里。
所以常见的习惯就是:

mkdir -p ~/ros2_ws/src

src/ 下面的外层 my_py_pubsub/
就是你的 ROS 2 包目录。

它的名字就是包名,所以以后你运行的时候会用到这个名字:

ros2 run my_py_pubsub talker

package.xml:这个包的身份证

package.xml 可以理解成 ROS 2 包的“身份证”或者“说明书”。

它通常会记录这些信息:

包名

版本

描述

作者 / 维护者

依赖项

setup.py:告诉系统“这个包怎么装、怎么跑”

setup.py 是 Python 包的安装配置文件。

它的作用包括:

声明 Python 模块

指定包名

配置可执行入口

告诉系统哪些脚本能被当成命令运行

其中最关键的一段,通常长这样:

entry_points={
'console_scripts': [
'talker = my_py_pubsub.talker:main',
'listener = my_py_pubsub.listener:main',
],
}

这段配置非常重要。

它的意思是:

当你执行:

ros2 run my_py_pubsub talker

ROS 2 实际上会去调用:

my_py_pubsub/talker.py

里面的:

main()

函数。

13. talker.py 和 listener.py 分别干嘛?

这两个就是你真正写的 ROS 2 节点代码。

talker.py

它是发布者节点,主要做三件事:

创建一个 publisher

定时生成消息

把消息发到 topic chatter

所以它负责“说话”。

listener.py

它是订阅者节点,主要做两件事:

创建一个 subscriber

收到 chatter 上的消息后打印出来

所以它负责“听话”。

这两个文件合起来,就是 ROS 2 最小的通信实验。

14. build/、install/、log/ 是什么?

这三个目录通常不是你手动创建的,
而是执行下面这个命令后自动生成的:

colcon build

它们分别代表不同阶段的构建结果。

build/

这里是编译过程中的中间文件。
可以理解成构建缓存和临时产物。

install/

这里是构建完成后的“安装结果”。

这个目录非常重要,因为构建完成后你通常要执行:

source ~/ros2_ws/install/setup.bash

这样系统才知道你自己写的包在哪里,才能用 ros2 run 找到它。

log/

这里是构建日志。
如果编译失败,很多时候可以来这里查问题。

所以这三个目录里,初学阶段你最需要理解的是:

install/ 很重要,因为它决定你的包能不能被 ROS 2 正确加载

Top comments (0)