跳转至

1.6 在vscode中编写ROS节点间发布订阅演示

约 879 个字 157 行代码 预计阅读时间 5 分钟

一、创建工作目录

在终端中,执行如下命令:

mkdir -p ~/ros_ws/src
这里我们创建的ros_ws目录就是我们的工作目录,也就是我们的项目存放目录。ros_ws里面的src目录,是我们存放程序源代码的。

进入ros_ws/src目录,执行如下命令:

cd ~/ros_ws/src
创建ros包py_pubsub,执行如下命令:
ros2 pkg create --build-type ament_python --node-name hello_publisher py_pubsub
命令解释:

  • ros2是ROS2中的平台命令,像ros2 pkgros2 run等都是以ros2开头的命令。也就是说ros2管理着一组命令。
    这里的pkg就是一个命令,是包命令。createpkg包命令的子命令,是创建命令。

  • --build-type是选择构建类型的参数,后面可带cmakeament_cmakeament_python,这都是指代的代码语言类型。cmakeament_cmake是c/c++语言,ament_python是python语言。

  • --node-name是节点名参数,后面就可以添加节点名,最后那个参数是包名称。

点击查看执行示例
执行示例.log
fotianmoyin@fotianmoyin-vm:~/ros_ws/src$ ros2 pkg create --build-type ament_python --node-name hello_publisher py_pubsub
going to create a new package
package name: py_pubsub
destination directory: /home/fotianmoyin/ros_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['fotianmoyin <fotianmoyin@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_python
dependencies: []
node_name: hello_publisher
creating folder ./py_pubsub
creating ./py_pubsub/package.xml
creating source folder
creating folder ./py_pubsub/py_pubsub
creating ./py_pubsub/setup.py
creating ./py_pubsub/setup.cfg
creating folder ./py_pubsub/resource
creating ./py_pubsub/resource/py_pubsub
creating ./py_pubsub/py_pubsub/__init__.py
creating folder ./py_pubsub/test
creating ./py_pubsub/test/test_copyright.py
creating ./py_pubsub/test/test_flake8.py
creating ./py_pubsub/test/test_pep257.py
creating ./py_pubsub/py_pubsub/hello_publisher.py

[WARNING]: Unknown license 'TODO: License declaration'.  This has been set in the package.xml, but no LICENSE file has been created.
It is recommended to use one of the ament license identitifers:
Apache-2.0
BSL-1.0
BSD-2.0
BSD-2-Clause
BSD-3-Clause
GPL-3.0-only
LGPL-3.0-only
MIT
MIT-0

我们用vscode【打开文件夹】方式打开我们的ros_ws工作目录,可以看到项目结构如下:

rosws

  • .vscode目录是vscode的配置目录。
  • log目录是我们的ROS插件自动生成的,是存储编译、运行中的日志记录的。
  • src目录里面存储的是我们的源程序。这里面有个py_pubsub目录,这个是我们创建的ROS包。在这个py_pubsub目录中还有个包含__init__.py文件的py_pubsub目录,这是python的包。
  • package.xml是ROS的包依赖配置文件。
  • setup.py是定义ROS编译配置的。
  • test目录是测试项目目录。
  • resource是资源存放目录。

二、编写发布者代码

我们打开我们的发布者节点hello_publisher.py文件,编辑代码如下:

hello_publisher.py
import rclpy  # ROS核心包
from rclpy.node import Node  # ROS节点定义类
from std_msgs.msg import String  # ROS标准消息字符串消息


class HelloPublisher(Node):
    def __init__(self):
        super().__init__("hello_publisher")
        self.publisher_ = self.create_publisher(
            String, "topic", 10
        )  # 创建一个发布者,发布的消息为String类型,消息标识为topic,消息缓存队列长度10
        timer_period = 0.5  # 定时器周期0.5秒
        self.timer = self.create_timer(timer_period, self.timer_callback)

    def timer_callback(self):
        msg = String()
        msg.data = "hello"
        self.publisher_.publish(msg)  # 发布消息
        self.get_logger().info(f'Publishing: "{msg.data}"')  # 打印日志


def main(args=None):
    rclpy.init(args=args)
    hello_publisher = HelloPublisher()  # 创建发布类实例
    rclpy.spin(hello_publisher)  # 附加发布类实例到执行器,这里执行器会持续运行,就像消息循环一样,直到被停止
    hello_publisher.destroy_node()  # 销毁发布类实例
    rclpy.shutdown()  # 关闭ROS执行器


if __name__ == "__main__":
    main()

三、编写订阅者代码

py_pubsub包中再新建一个hello_subscriber.py订阅者节点文件,文件内容如下:

hello_subscriber.py
import rclpy  # ROS核心包
from rclpy.node import Node  # ROS节点定义类
from std_msgs.msg import String  # ROS标准消息字符串消息


class HelloSubscriber(Node):
    def __init__(self):
        super().__init__("hello_subscriber")
        self.subscription = self.create_subscription(
            String, "topic", self.listener_callback, 10
        )  # 创建一个订阅者,订阅topic标识的消息,消息类型是String,消息缓冲队列长度10
        self.subscription  # 自引用一下,消除未引用错误提示

    def listener_callback(self, msg):
        self.get_logger().info(f'I heard: "{msg.data}"')  # 打印日志


def main(args=None):
    rclpy.init(args=args)
    hello_subscriber = HelloSubscriber()  # 创建订阅类实例
    rclpy.spin(hello_subscriber)  # 附加订阅类实例到执行器,这里执行器会持续运行,就像消息循环一样,直到被停止
    hello_subscriber.destroy_node()  # 销毁订阅类实例
    rclpy.shutdown()  # 关闭ROS执行器


if __name__ == "__main__":
    main()

四、修改setup.py文件

修改setup.py文件,内容如下:

setup.py
from setuptools import find_packages, setup

package_name = "py_pubsub"

setup(
    name=package_name,
    version="0.0.0",
    packages=find_packages(exclude=["test"]),
    data_files=[
        ("share/ament_index/resource_index/packages", ["resource/" + package_name]),
        ("share/" + package_name, ["package.xml"]),
    ],
    install_requires=["setuptools"],
    zip_safe=True,
    maintainer="fotianmoyin",
    maintainer_email="fotianmoyin@todo.todo",
    description="TODO: Package description",
    license="TODO: License declaration",
    tests_require=["pytest"],
    entry_points={
        "console_scripts": [
            "publisher = py_pubsub.hello_publisher:main",  # 这行修改发布者节点名称为:publisher
            "subscriber = py_pubsub.hello_subscriber:main",  # 这行是新加的,添加订阅者节点,名称为:subscriber
        ],
    },
)

五、使用colcon编译项目

Ctrl+J,打开命令窗口,运行编译命令如下:

colcon build
rosws_build

处理编译警告

有个警告,内容如下:

SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
使用如下命令可以查看当前setuptools的版本:
pip show setuptools
输出如下:
fotianmoyin@fotianmoyin-vm:~/ros_ws$ pip show setuptools
Name: setuptools
Version: 59.6.0
Summary: Easily download, build, install, upgrade, and uninstall Python packages
Home-page: https://github.com/pypa/setuptools
Author: Python Packaging Authority
Author-email: distutils-sig@python.org
License: UNKNOWN
Location: /usr/lib/python3/dist-packages
Requires: 
Required-by: action-tutorials-py, ament-copyright, ament-cppcheck, ament-cpplint, ament-flake8, ament-index-python, ament-lint, ament-lint-cmake, ament-pep257, ament-uncrustify, ament-xmllint, catkin-pkg-modules, colcon-core, demo-nodes-py, domain-coordinator, examples-rclpy-executors, examples-rclpy-minimal-action-client, examples-rclpy-minimal-action-server, examples-rclpy-minimal-client, examples-rclpy-minimal-publisher, examples-rclpy-minimal-service, examples-rclpy-minimal-subscriber, launch, launch-ros, launch-testing, launch-testing-ros, launch-xml, launch-yaml, py-pubsub, quality-of-service-demo-py, rqt-action, rqt-bag, rqt-bag-plugins, rqt-console, rqt-graph, rqt-gui, rqt-gui-py, rqt-msg, rqt-plot, rqt-publisher, rqt-py-console, rqt-reconfigure, rqt-service-caller, rqt-shell, rqt-srv, rqt-topic, sensor-msgs-py, sros2, teleop-twist-keyboard, tf2-ros-py, tf2-tools, topic-monitor
可以看到我们setuptools版本是59.6.0 之所以报上面那个警告,因为setuptools工具版本高了,降低到58.2.0就行了,可以执行以下命令降级:
pip install -i https://pypi.doubanio.com/simple setuptools==58.2.0

点击查看执行示例
执行示例.log
fotianmoyin@fotianmoyin-vm:~/ros_ws$ pip install -i https://pypi.doubanio.com/simple setuptools==58.2.0
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: https://pypi.doubanio.com/simple
Collecting setuptools==58.2.0
Downloading https://mirrors.cloud.tencent.com/pypi/packages/41/f4/a7ca4859317232b1efb64a826b8d2d7299bb77fb60bdb08e2bd1d61cf80d/setuptools-58.2.0-py3-none-any.whl (946 kB)
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 946.1/946.1 KB 749.6 kB/s eta 0:00:00
Installing collected packages: setuptools
Successfully installed setuptools-58.2.0

再次执行编译,输出如下:

fotianmoyin@fotianmoyin-vm:~/ros_ws$ colcon build
Starting >>> py_pubsub
Finished <<< py_pubsub [2.97s]          

Summary: 1 package finished [5.23s]
没有警告了

从左侧栏中,我们看到ros_ws中多了两个目录buildinstall
build目录是编译中间文件存放目录
install目录是编译后的文件存放目录
也就是说我们最终运行ros程序时,运行的是install目录中的程序。

六、运行示例程序

附加编译后的程序到当前shell,运行如下命令:

. install/local_setup.sh
运行如下命令,启动发布者节点:
ros2 run py_pubsub publisher
ros2 run是运行节点命令,py_pubsub是节点所在包名,publisher是我们在setup.py文件中配置的节点名称

rosws_run1

通过点击终端栏的+号,再打开一个终端

vscode_newshell

在新开的终端中,附加编译后的程序到当前shell,运行如下命令:

. install/local_setup.sh
运行如下命令,启动订阅者节点:
ros2 run py_pubsub subscriber
rosws_run2

可以看到,两个终端间已经能够进行发布订阅演示。

注:结束程序,可以在shell中按Ctrl+C

源码下载